Commit 04547096 authored by Per Cederqvist's avatar Per Cederqvist

First commit. This does not yet check @aarg{} constructs, but it

already finds many errors in Protocol-A.texi.
parent af207fb1
# Check @aarg{} and @rarg{} usage in Protocol-A.texi.
import sys
import types
class reader_eof(Exception):
pass
class reader:
def __init__(self, file):
self.__filename = file
self.__file = open(file, "r")
self.__line_no = 0
self.__line = []
self.__eof = 0
def filename(self):
return self.__filename
def ungetc(self, c):
self.__line.insert(0, c)
def getc_eofok(self):
if self.__line == []:
if self.__eof:
return None
line = self.__file.readline()
if line == '':
self.__eof = 1
return None
self.__line = list(line)
self.__line_no += 1
ret = self.__line[0]
del self.__line[0]
return ret
def getc(self):
c = self.getc_eofok()
if c == None:
raise reader_eof
return c
def line_no(self):
return self.__line_no
class lexer:
def __init__(self, file):
self.__reader = reader(file)
self.__errfound = 0
self.__findex = None
def run(self):
while 1:
c = self.__reader.getc_eofok()
if c == None:
return self.__errfound
if c == '@':
self.__toplevel_at()
def __toplevel_at(self):
line_no = self.__reader.line_no()
c = self.__reader.getc()
if c in '{}@-"*':
return
cmd = ""
while 1:
if c.isalpha() or c in '_"':
cmd = cmd + c
c = self.__reader.getc()
elif c in ' \t\n{@=-':
assert cmd != ''
if c == '{':
arg = self.__read_arg()
elif c == ' ' and cmd not in ['tab']:
arg = self.__read_line()
else:
arg = None
if c == '@':
self.__reader.ungetc(c)
if hasattr(self, 'toplevel_' + cmd):
getattr(self, 'toplevel_' + cmd)(arg, line_no)
else:
self.error(line_no, "unknown command @%s{}" % cmd)
return
else:
self.error(line_no, "bad command ``@%s%s''" % (cmd, c))
return
def __read_line(self):
line = ""
while 1:
c = self.__reader.getc()
if c == '\n':
return line
line = line + c
def ignore(self, arg, line_no):
pass
toplevel_setfilename = ignore
toplevel_settitle = ignore
toplevel_setchapternewpage = ignore
toplevel_set = ignore
toplevel_macro = ignore
toplevel_code = ignore
toplevel_end = ignore
toplevel_ifinfo = ignore
toplevel_value = ignore
toplevel_copyright = ignore
toplevel_iftex = ignore
toplevel_parindent = ignore
toplevel_ifinfo = ignore
toplevel_begin = ignore
toplevel_titlepage = ignore
toplevel_title = ignore
toplevel_subtitle = ignore
toplevel_author = ignore
toplevel_font = ignore
toplevel_ignore = ignore
toplevel_tensltt = ignore
toplevel_page = ignore
toplevel_vskip = ignore
toplevel_ifnothtml = ignore
toplevel_contents = ignore
toplevel_dircategory = ignore
toplevel_direntry = ignore
toplevel_ifhtml = ignore
toplevel_html = ignore
toplevel_ifnottex = ignore
toplevel_top = ignore
toplevel_uref = ignore
toplevel_menu = ignore
toplevel_chapter = ignore
toplevel_uref = ignore
toplevel_footnote = ignore
toplevel_email = ignore
toplevel_penalty = ignore
toplevel_section = ignore
toplevel_table = ignore
toplevel_asis = ignore
toplevel_item = ignore
toplevel_req = ignore
toplevel_subsection = ignore
toplevel_itemize = ignore
toplevel_bullet = ignore
toplevel_multitable = ignore
toplevel_tab = ignore
toplevel_aux = ignore
toplevel_samp = ignore
toplevel_pxref = ignore
toplevel_errorcode = ignore
toplevel_misc = ignore
toplevel_type = ignore
toplevel_field = ignore
toplevel_dfn = ignore
toplevel_conftype = ignore
toplevel_command = ignore
toplevel_ref = ignore
toplevel_var = ignore
toplevel_subsubsection = ignore
toplevel_priv = ignore
toplevel_emph = ignore
toplevel_enumerate = ignore
toplevel_tindex = ignore # FIXME: check 'em?
toplevel_xref = ignore
toplevel_itemx = ignore
toplevel_ae = ignore
toplevel_i = ignore
toplevel_subheading = ignore
toplevel_c = ignore
toplevel_t = ignore
toplevel_aa = ignore
toplevel_async = ignore
toplevel_unnumbered = ignore
toplevel_printindex = ignore
toplevel_example = ignore
def toplevel_node(self, arg, line_no):
if self.__findex != None:
self.__findex = None
for (argname, [lineno, usage]) in self.__args.items():
if usage == 0:
self.error(lineno,
"Undocumented argument ``%s''" % (argname, ))
self.__findex = None
self.__node_name = arg
self.__node_start = line_no
def toplevel_findex(self, arg, line_no):
if self.__node_name != arg:
self.error(line_no, "@node/@findex mismatch: %s..." % arg)
self.error(line_no, "...inside node %s" % self.__node_name)
return
if self.__findex != None:
self.error(line_no, "multiple @findex in single @node")
return
self.__findex = arg
self.__args = {}
self.__tokens = []
if self.__get_token() != '@example':
self.error(self.__reader.line_no(), "missing @example")
return
self.__parse_request()
def toplevel_rarg(self, arg, line_no):
if self.__findex == None:
self.error(line_no, "@rarg outside @findex node")
return
if not self.__args.has_key(arg):
self.error(line_no, "undefined argument ``%s''" % (arg, ))
return
self.__args[arg][1] += 1
def toplevel_aarg(self, arg, line_no):
pass
# FIXME
def toplevel_bye(self, arg, line_no):
if self.__findex != None:
self.error(self.__reader.line_no(), "unterminated @findex node")
def __parse_request(self):
self.__tokens = []
req = self.__get_token()
if req != self.__findex:
self.error(self.__reader.line_no(),
"wrong request name ``%s''" % req)
return
if self.__get_token() != '[':
self.error(self.__reader.line_no(), "missing ``[''")
return
nr = self.__get_token()
if type(nr) != types.IntType:
self.error(self.__reader.line_no(), "bad request number")
if self.__get_token() != ']':
self.error(self.__reader.line_no(), "missing ``]''")
return
paren = self.__get_token()
if paren == '(':
next = self.__get_token()
if next != ')':
self.__unget_token(next)
self.__parse_request_arg()
next = self.__get_token()
if next != ')':
self.error(self.__reader.line_no(),
"missing close parenthesis after arguments")
return
elif paren == '((':
self.__parse_request_arg()
next = self.__get_token()
while next == ';':
self.__parse_request_arg()
next = self.__get_token()
if next != '))':
self.error(self.__reader.line_no(),
"missing double close parenthesis after arguments")
return
else:
self.error(self.__reader.line_no(),
"missing argument list")
return
if self.__get_token() != '->':
self.error(self.__reader.line_no(), "missing ``->''")
return
if self.__get_token() != '(':
self.error(self.__reader.line_no(), "missing ``('' for result")
return
next = self.__get_token()
if next != ')':
self.__unget_token(next)
ret_type = self.__parse_type()
next = self.__get_token()
if next != ')':
self.error(self.__reader.line_no(), "missing ``)'' for result")
return
if self.__get_token() != ';':
self.error(self.__reader.line_no(), "missing final ``;''")
return
if self.__get_token() != '@end':
self.error(self.__reader.line_no(), "extra garbage found")
return
return
def __parse_type(self):
token = self.__get_token()
if token == 'ARRAY':
tp = self.__get_token()
if self.__bad_type(tp):
return None
return token + " " + tp
else:
if self.__bad_type(token):
return None
return token
def __bad_type(self, tp):
if tp in ['INT8', 'INT16', 'INT32']:
return 0
ok = 1
if len(tp) < 0:
ok = 0
if ok and not tp[0].isupper():
ok = 0
for c in tp[1:]:
if not c.isalpha() and c != '-':
ok = 0
if ok and tp[-1] == '-':
ok = 0
if not ok:
self.error(self.__reader.line_no(), "bad type name ``%s''" % (tp,))
return not ok
def __bad_arg(self, arg):
ok = 1
if len(arg) < 0:
ok = 0
if ok and not arg[0].islower():
ok = 0
for c in arg[1:]:
if not c.islower() and c != '-':
ok = 0
if ok and arg[-1] == '-':
ok = 0
if not ok:
if arg == '))':
self.error(self.__reader.line_no(),
"extra semicolon after last arg")
else:
self.error(self.__reader.line_no(),
"bad argument ``%s''" % (arg,))
return not ok
def __parse_request_arg(self):
argname = self.__get_token()
if self.__bad_arg(argname):
return
if self.__get_token() != ':':
self.error(self.__reader.line_no(), "missing ``:'' after argument")
return
tp = self.__parse_type()
if tp == None:
return
if self.__args.has_key(argname):
self.error(self.__reader.line_no(),
"argument name ``%s'' used twice" % (argname, ))
return
self.__args[argname] = [self.__reader.line_no(), 0]
def __unget_token(self, token):
self.__tokens.insert(0, token)
def __get_token(self):
if len(self.__tokens) > 0:
res = self.__tokens[0]
del self.__tokens[0]
return res
c = self.__reader.getc()
while c.isspace():
c = self.__reader.getc()
if c.isalpha():
res = c
while 1:
c = self.__reader.getc()
if not c.isalpha() and c not in "-" and not c.isdigit():
if c.isdigit():
self.error(self.__reader.line_no(),
"bad token ``%s''" % (res + c))
self.__reader.ungetc(c)
return res
res = res + c
elif c in '[];:':
return c
elif c in '()':
d = self.__reader.getc()
if c != d:
self.__reader.ungetc(d)
return c
else:
return c + d
elif c.isdigit():
res = c
while 1:
c = self.__reader.getc()
if not c.isdigit():
if c.isalpha():
self.error(self.__reader.line_no(),
"bad token ``%s''" % (res + c))
self.__reader.ungetc(c)
if res[0] == '0' and len(res) > 1:
self.error(self.__reader.line_no(),
"bad number ``%s''" % (res,))
return int(res)
res = res + c
elif c == '-':
d = self.__reader.getc()
if d == '>':
return '->'
else:
self.error(self.__reader.line_no(),
"bad token ``%s%s''" % (c, d))
self.__reader.ungetc(d)
return c
elif c == '@':
res = c
while 1:
c = self.__reader.getc()
if not c.isalpha():
self.__reader.ungetc(c)
return res
res = res + c
else:
self.error(self.__reader.line_no(),
"bad character ``%s''" % (c,))
return c
def __read_arg(self):
arg = ""
while 1:
c = self.__reader.getc()
if c == '}':
return arg
else:
arg = arg + c
def error(self, line_no, errmsg):
sys.stderr.write("%s:%d:%s\n" % (self.__reader.filename(),
line_no, errmsg))
self.__errfound = 1
if __name__ == '__main__':
l = lexer(sys.argv[1])
sys.exit(l.run())
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment