Commit 98388b66 authored by Poul-Henning Kamp's avatar Poul-Henning Kamp

Rewrite to split lex and parsing into separate steps

parent 2e0f09fc
...@@ -169,20 +169,15 @@ def lwrap(s, width=64): ...@@ -169,20 +169,15 @@ def lwrap(s, width=64):
return ll return ll
def quote(s): #######################################################################
return s.replace("\"", "\\\"")
def indent(p, n):
n = len(p.expandtabs()) + n
p = "\t" * int(n / 8)
p += " " * int(n % 8)
return p
####################################################################### inputline = None
def err(str, warn=True): def err(str, warn=True):
if inputline is not None:
print("While parsing line:\n\t", inputline)
if opts.strict or not warn: if opts.strict or not warn:
print("ERROR: " + str, file=sys.stderr) print("ERROR: " + str, file=sys.stderr)
exit(1) exit(1)
...@@ -203,13 +198,20 @@ enum_values = {} ...@@ -203,13 +198,20 @@ enum_values = {}
class ctype(object): class ctype(object):
def __init__(self, vt, ct): def __init__(self, wl):
self.vt = vt
self.ct = ct
self.nm = None self.nm = None
self.defval = None self.defval = None
self.spec = None self.spec = None
self.vt = wl.pop(0)
self.ct = ctypes.get(self.vt)
if self.ct is None:
err("Expected type got '%s'" % self.vt, warn=False)
if len(wl) > 0 and wl[0] == "{":
if self.vt != "ENUM":
err("Only ENUMs take {...} specs", warn=False)
self.add_spec(wl)
def __str__(self): def __str__(self):
s = "<" + self.vt s = "<" + self.vt
if self.nm is not None: if self.nm is not None:
...@@ -220,6 +222,32 @@ class ctype(object): ...@@ -220,6 +222,32 @@ class ctype(object):
s += " SPEC=" + str(self.spec) s += " SPEC=" + str(self.spec)
return s + ">" return s + ">"
def set_defval(self, x):
if self.vt == "ENUM":
if x[0] == '"' and x[-1] == '"':
x = x[1:-1]
elif x[0] == "'" and x[-1] == "'":
x = x[1:-1]
self.defval = x
def add_spec(self, wl):
assert self.vt == "ENUM"
assert wl.pop(0) == "{"
self.spec = []
while True:
x = wl.pop(0)
if x[0] == '"' and x[-1] == '"':
x = x[1:-1]
elif x[0] == "'" and x[-1] == "'":
x = x[1:-1]
assert len(x) > 0
self.spec.append(x)
enum_values[x] = True
w = wl.pop(0)
if w == "}":
break
assert w == ","
def vcl(self): def vcl(self):
if self.vt == "STRING_LIST": if self.vt == "STRING_LIST":
return "STRING" return "STRING"
...@@ -238,118 +266,102 @@ class ctype(object): ...@@ -238,118 +266,102 @@ class ctype(object):
jl[-1].pop(-1) jl[-1].pop(-1)
def vtype(txt): def lex(l):
j = len(txt) wl = []
for i in (',', ' ', '\n', '\t'): s = 0
x = txt.find(i) for i in range(len(l)):
if x > 0: c = l[i]
j = min(j, x)
t = txt[:j]
r = txt[j:].lstrip()
if t not in ctypes:
err("Did not recognize type <%s>" % txt)
ct = ctype(t, ctypes[t])
if t != "ENUM":
return ct, r
assert r[0] == '{'
e = r[1:].split('}', 1)
r = e[1].lstrip()
e = e[0].split(',')
ct.spec = []
for i in e:
j = i.strip()
enum_values[j] = True
ct.spec.append(j)
return ct, r
def arg(txt):
a, s = vtype(txt)
if len(s) == 0 or s[0] == ',':
return a, s
i = s.find('=')
j = s.find(',')
if j < 0:
j = len(s)
if j < i:
i = -1
if i < 0:
i = s.find(',')
if i < 0:
i = len(s)
a.nm = s[:i].rstrip()
s = s[i:]
return a, s
a.nm = s[:i].rstrip()
s = s[i + 1:].lstrip()
if s[0] == '"' or s[0] == "'":
m = re.match("(['\"]).*?(\\1)", s)
if not m:
err("Unbalanced quote")
a.defval = s[:m.end()]
if a.vt == "ENUM":
a.defval = a.defval[1:-1]
s = s[m.end():]
else:
i = s.find(',')
if i < 0:
i = len(s)
a.defval = s[:i].rstrip()
s = s[i:]
if a.vt == "ENUM" and a.defval not in a.spec:
err("ENUM default value <%s> not valid" % a.defval, warn=False)
return a, s if s == 0 and re.match('[0-9a-zA-Z_.-]', c):
wl.append(c)
s = 3
continue
if s == 3:
if re.match('[0-9a-zA-Z_.-]', c):
wl[-1] += c
continue
s = 0
def nmlegal(nm): if s == 0 and c in (' ', '\t', '\n', '\r'):
return re.match('^[a-zA-Z0-9_]+$', nm) continue
if s == 0 and c in ('(', '{', '}', ')', ',', '='):
wl.append(c)
elif s == 0 and c in ('"', "'"):
sep = c
s = 1
wl.append(c)
elif s == 1:
if c == '\\':
s = 2
else:
wl[-1] += c
if c == sep:
s = 0
elif s == 2:
wl[-1] += c
s = 1
else:
err("Syntax error at char", i, "'%s'" % c, warn=False)
if s != 0:
err("Syntax error at char", i, "'%s'" % c, warn=False)
return wl
# XXX cant have ( or ) in an argument default value
class prototype(object): class prototype(object):
def __init__(self, st, retval=True, prefix=""): def __init__(self, st, retval=True, prefix=""):
global inputline
self.st = st self.st = st
self.obj = None self.obj = None
ll = st.line[1] inputline = st.line[1]
wl = lex(st.line[1])
if retval: if retval:
self.retval, s = vtype(ll) self.retval = ctype(wl)
else:
self.retval = None self.bname = wl.pop(0)
s = ll if not re.match("^[a-zA-Z.][a-zA-Z0-9_]*$", self.bname):
i = s.find("(") err("%s(): Illegal name\n" % self.nname, warn=False)
assert i > 0
self.prefix = prefix self.prefix = prefix
self.bname = s[:i].strip()
self.name = self.prefix + self.bname self.name = self.prefix + self.bname
self.vcc = st.vcc self.vcc = st.vcc
if not nmlegal(self.cname()): if not re.match('^[a-zA-Z_][a-zA-Z0-9_]*$', self.cname()):
err("%s(): Illegal name\n" % self.name, warn=False) err("%s(): Illegal C-name\n" % self.cname(), warn=False)
s = s[i:].strip()
assert s[0] == "(" x = wl.pop(0)
assert s[-1] == ")" if x != "(":
s = s[1:-1].lstrip() err("Syntax error: Expected '(', got '%s'" % x, warn=False)
self.args = []
x = wl.pop(-1)
if x != ")":
err("Syntax error: Expected ')', got '%s'" % x, warn=False)
names = {} names = {}
while len(s) > 0: self.args = []
a, s = arg(s) while len(wl) > 0:
if a.nm is not None: t = ctype(wl)
if not nmlegal(a.nm): self.args.append(t)
err("%s(): illegal argument name '%s'\n" if not len(wl):
% (self.name, a.nm), warn=False)
if a.nm in names:
err("%s(): duplicate argument name '%s'\n"
% (self.name, a.nm), warn=False)
names[a.nm] = True
self.args.append(a)
s = s.lstrip()
if len(s) == 0:
break break
assert s[0] == ',' x = wl.pop(0)
s = s[1:].lstrip() if x == ",":
continue
if x in names:
err("%s(): Duplicate argument name" % x, warn=False)
names[x] = True
t.nm = x
if not len(wl):
break
if wl[0] == "=":
wl.pop(0)
t.set_defval(wl.pop(0))
if not len(wl):
break
assert wl.pop(0) == ","
inputline = None
def cname(self, pfx=False): def cname(self, pfx=False):
r = self.name.replace(".", "_") r = self.name.replace(".", "_")
...@@ -429,7 +441,7 @@ class prototype(object): ...@@ -429,7 +441,7 @@ class prototype(object):
def json(self, jl, cfunc): def json(self, jl, cfunc):
ll = [] ll = []
self.retval.json(ll) self.retval.json(ll)
ll.append(cfunc) ll.append('Vmod_%s_Func.%s' % (self.vcc.modname, cfunc))
for i in self.args: for i in self.args:
i.json(ll) i.json(ll)
jl.append(ll) jl.append(ll)
...@@ -613,18 +625,14 @@ class s_function(stanza): ...@@ -613,18 +625,14 @@ class s_function(stanza):
fo.write("\t" + self.proto.cname(pfx=True) + ",\n") fo.write("\t" + self.proto.cname(pfx=True) + ",\n")
def json(self, jl): def json(self, jl):
jl.append([ jl.append(["$FUNC", "%s" % self.proto.name])
"$FUNC", self.proto.json(jl[-1], self.proto.cname())
"%s" % self.proto.name,
])
self.proto.json(jl[-1], 'Vmod_%s_Func.%s' %
(self.vcc.modname, self.proto.cname()))
class s_object(stanza): class s_object(stanza):
def parse(self): def parse(self):
self.proto = prototype(self, retval=False) self.proto = prototype(self, retval=False)
self.proto.retval = vtype('VOID')[0] self.proto.retval = ctype(['VOID'])
self.proto.obj = "x" + self.proto.name self.proto.obj = "x" + self.proto.name
self.init = copy.copy(self.proto) self.init = copy.copy(self.proto)
...@@ -695,13 +703,11 @@ class s_object(stanza): ...@@ -695,13 +703,11 @@ class s_object(stanza):
l2 = ["$INIT"] l2 = ["$INIT"]
ll.append(l2) ll.append(l2)
self.init.json(l2, self.init.json(l2, self.init.name)
'Vmod_%s_Func.%s' % (self.vcc.modname, self.init.name))
l2 = ["$FINI"] l2 = ["$FINI"]
ll.append(l2) ll.append(l2)
self.fini.json(l2, self.fini.json(l2, self.fini.name)
'Vmod_%s_Func.%s' % (self.vcc.modname, self.fini.name))
for i in self.methods: for i in self.methods:
i.json(ll) i.json(ll)
...@@ -731,13 +737,8 @@ class s_method(stanza): ...@@ -731,13 +737,8 @@ class s_method(stanza):
fo.write('\t' + self.proto.cname(pfx=True) + ",\n") fo.write('\t' + self.proto.cname(pfx=True) + ",\n")
def json(self, jl): def json(self, jl):
jl.append([ jl.append(["$METHOD", self.proto.name[len(self.pfx)+1:]])
"$METHOD", self.proto.json(jl[-1], self.proto.cname())
self.proto.name[len(self.pfx)+1:]
])
self.proto.json(jl[-1],
'Vmod_%s_Func.%s' %
(self.vcc.modname, self.proto.cname()))
####################################################################### #######################################################################
...@@ -867,7 +868,7 @@ class vcc(object): ...@@ -867,7 +868,7 @@ class vcc(object):
j.json(jl) j.json(jl)
bz = bytearray(json.dumps(jl, separators=(",", ":")), bz = bytearray(json.dumps(jl, separators=(",", ":")),
encoding = "ascii") + b"\0" encoding="ascii") + b"\0"
fo.write("\nstatic const char Vmod_Json[%d] = {\n" % len(bz)) fo.write("\nstatic const char Vmod_Json[%d] = {\n" % len(bz))
t = "\t" t = "\t"
for i in bz: for i in bz:
......
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