10 class SyntaxError(Exception):
13 class DBParser(object):
17 def _syntax_error(self, txt=None):
18 txt = txt and ' (%s)' % txt or ''
19 raise SyntaxError("Syntax error in line %d%s" % (self._lineno, txt))
22 sys.stderr.write("Warning (line %d): %s\n" % (self._lineno, txt))
24 def _parse_band_def(self, bname, banddef, dupwarn=True):
27 freqs, line = line.split(',', 1)
32 flags = [f.upper() for f in line.split(',') if f]
35 freqs, bw = freqs.split('@')
41 start, end = freqs.split('-')
45 self._syntax_error("band must have frequency range")
49 if not f in band_flags:
50 self._syntax_error("Invalid band flag")
53 b = (start, end, bw, fl)
54 self._banddup[bname] = bname
55 if b in self._bandrev:
57 self._warn('Duplicate band definition ("%s" and "%s")' % (
58 bname, self._bandrev[b]))
59 self._banddup[bname] = self._bandrev[b]
60 self._bands[bname] = b
61 self._bandrev[b] = bname
62 self._bandline[bname] = self._lineno
64 def _parse_band(self, line):
66 bname, line = line.split(':', 1)
68 self._syntax_error("'band' keyword must be followed by name")
70 self._syntax_error("band name must be followed by colon")
72 self._parse_band_def(bname, line)
74 def _parse_power(self, line):
76 pname, line = line.split(':', 1)
78 self._syntax_error("'power' keyword must be followed by name")
80 self._syntax_error("power name must be followed by colon")
82 self._parse_power_def(pname, line)
84 def _parse_power_def(self, pname, line, dupwarn=True):
91 max_eirp_ptp) = line.split(',')
92 max_ant_gain = float(max_ant_gain)
93 max_ir_ptmp = float(max_ir_ptmp)
94 max_ir_ptp = float(max_ir_ptp)
95 max_eirp_ptmp = float(max_eirp_ptmp)
96 max_eirp_ptp = float(max_eirp_ptp)
98 self._syntax_error("invalid power data")
102 if not environ in ('I', 'O', ' '):
103 self._syntax_error("Invalid environment specifier")
105 p = (environ, max_ant_gain, max_ir_ptmp,
106 max_ir_ptp, max_eirp_ptmp, max_eirp_ptp)
107 self._powerdup[pname] = pname
108 if p in self._powerrev:
110 self._warn('Duplicate power definition ("%s" and "%s")' % (
111 pname, self._powerrev[p]))
112 self._powerdup[pname] = self._powerrev[p]
113 self._power[pname] = p
114 self._powerrev[p] = pname
115 self._powerline[pname] = self._lineno
117 def _parse_country(self, line):
119 cname, line = line.split(':', 1)
121 self._syntax_error("'country' keyword must be followed by name")
123 self._syntax_error("extra data at end of country line")
125 self._syntax_error("country name must be followed by colon")
127 if not cname in self._countries:
128 self._countries[cname] = []
129 self._current_country = self._countries[cname]
130 self._current_country_name = cname
132 def _parse_country_item(self, line):
135 band, pname = line[1:].split('),')
136 bname = 'UNNAMED %d' % self._lineno
137 self._parse_band_def(bname, band, dupwarn=False)
139 self._syntax_error("Badly parenthesised band definition")
142 bname, pname = line.split(',', 1)
144 self._syntax_error("country definition must have band")
146 self._syntax_error("country definition must have power")
148 self._syntax_error("country definition must have band and power")
151 if not pname[-1] == ')':
152 self._syntax_error("Badly parenthesised power definition")
154 pname = 'UNNAMED %d' % self._lineno
155 self._parse_power_def(pname, power, dupwarn=False)
157 if not bname in self._bands:
158 self._syntax_error("band does not exist")
159 if not pname in self._power:
160 self._syntax_error("power does not exist")
161 self._bands_used[bname] = True
162 self._power_used[pname] = True
163 # de-duplicate so binary database is more compact
164 bname = self._banddup[bname]
165 pname = self._powerdup[pname]
167 if tup in self._current_country:
168 self._warn('Rule "%s, %s" added to "%s" twice' % (
169 bname, pname, self._current_country_name))
171 self._current_country.append((bname, pname))
174 self._current_country = None
178 self._bands_used = {}
179 self._power_used = {}
191 line = line.replace(' ', '').replace('\t', '')
192 line = line.split('#')[0]
195 if line[0:4] == 'band':
196 self._parse_band(line[4:])
197 self._current_country = None
198 elif line[0:5] == 'power':
199 self._parse_power(line[5:])
200 self._current_country = None
201 elif line[0:7] == 'country':
202 self._parse_country(line[7:])
203 elif self._current_country is not None:
204 self._parse_country_item(line)
206 self._syntax_error("Expected band, power or country definition")
209 for k, v in self._countries.iteritems():
211 for k in k.split(','):
212 countries[k] = tuple(v)
214 for k, v in self._bands.iteritems():
215 if k in self._bands_used:
216 bands[self._banddup[k]] = v
218 # we de-duplicated, but don't warn again about the dupes
219 if self._banddup[k] == k:
220 self._lineno = self._bandline[k]
221 self._warn('Unused band definition "%s"' % k)
223 for k, v in self._power.iteritems():
224 if k in self._power_used:
225 power[self._powerdup[k]] = v
227 # we de-duplicated, but don't warn again about the dupes
228 if self._powerdup[k] == k:
229 self._lineno = self._powerline[k]
230 self._warn('Unused power definition "%s"' % k)
231 return bands, power, countries
233 def create_rules(countries):
235 for c in countries.itervalues():
240 def create_collections(countries):
242 for c in countries.itervalues():
247 if __name__ == '__main__':
250 b, p, c = p.parse(sys.stdin)
254 print create_rules(c)
255 print create_collections(c)