diff --git a/contrib/nitcc/src/autom.nit b/contrib/nitcc/src/autom.nit index 66081eb87f..edb6a23ff2 100644 --- a/contrib/nitcc/src/autom.nit +++ b/contrib/nitcc/src/autom.nit @@ -1091,7 +1091,7 @@ private class DFAGenerator add("\t\tvar t = new MyNToken\n") add("\t\tt.text = position.extract(source)\n") else - add("\t\tvar t = new {token.acname}\n") + add("\t\tvar t = new {token.ast_type.to_nit}\n") var ttext = token.text if ttext == null then add("\t\tt.text = position.extract(source)\n") diff --git a/contrib/nitcc/src/grammar.nit b/contrib/nitcc/src/grammar.nit index 85bc12ecab..f2fe192166 100644 --- a/contrib/nitcc/src/grammar.nit +++ b/contrib/nitcc/src/grammar.nit @@ -29,8 +29,8 @@ class Gram do var res = new FlatBuffer for p in prods do - if p.spe != null then - res.append("{p.name} \{-> {p.spe.name}\}=\n") + if not p.is_ast then + res.append("{p.name} \{-> {p.ast_type}\}=\n") else res.append("{p.name} =\n") end @@ -339,12 +339,14 @@ class Gram var cname = "_plus{plusizes.length}" var prod = new Production("{e}+") prod.cname = cname - prod.acname = "Nodes[{e.acname}]" + prod.ast_type = e.ast_type.as_array prods.add(prod) var alt1 = prod.new_alt("{cname}_one", e) + alt1.trans = true alt1.codes = [new CodeNewNodes(alt1), new CodeGet(0), new CodeAdd: Code] var alt2 = prod.new_alt("{cname}_more", prod, e) alt2.codes = [new CodeGet(0), new CodeGet(1), new CodeAdd: Code] + alt2.trans = true plusizes[e] = prod return prod end @@ -370,12 +372,14 @@ class Gram var cname = "_opt{quesizes.length}" var prod = new Production("{e}?") prod.cname = cname - prod.acname = "nullable {e.acname}" + prod.ast_type = e.ast_type.as_nullable prods.add(prod) var a1 = prod.new_alt("{cname}_one", e) + a1.trans = true a1.codes = [new CodeGet(0)] var a0 = prod.new_alt0("{cname}_none") a0.codes = [new CodeNull] + a0.trans = true quesizes[e] = prod return prod end @@ -409,9 +413,9 @@ class Gram for t in tokens do if t.name == "Eof" then - g.add "redef class {t.acname}" + g.add "redef class NEof" else - g.add "class {t.acname}" + g.add "class {t.ast_type.to_nit}" g.add "\tsuper NToken" end g.add "\tredef fun node_name do return \"{t.name.escape_to_nit}\"" @@ -421,10 +425,9 @@ class Gram var ps = prods.to_a ps.add_all(ast_prods) for p in ps do - if p.spe == null and not p.altone then - if p.name.has_suffix("?") or p.name.has_suffix("+") then continue + if p.is_ast and not p.altone then g.add "# Production {p}" - g.add "class {p.acname}" + g.add "class {p.ast_type.to_nit}" g.add "\tsuper NProd" g.add "\tredef fun node_name do return \"{p.name.escape_to_nit}\"" g.add "end" @@ -439,14 +442,16 @@ class Gram if p.altone then g.add "\tsuper NProd" else - g.add "\tsuper {p.acname}" + g.add "\tsuper {p.ast_type.to_nit}" end g.add "\tredef fun node_name do return \"{a.name.escape_to_nit}\"" var initarg = new Array[String] for i in [0..a.elems.length[ do g.add "\t# Children {i}: {a.elems[i]}" - g.add "\tvar n_{a.elemname(i)}: {a.elems[i].acname}" - initarg.add("n_{a.elemname(i)}: {a.elems[i].acname}") + var t = a.elems[i].ast_type.to_nit + var n = a.elemname(i) + g.add "\tvar n_{n}: {t}" + initarg.add("n_{n}: {t}") end g.add "\tredef fun number_of_children do return {a.elems.length}" g.add "\tredef fun child(i) do" @@ -474,21 +479,24 @@ class Production # Is self the accept production var accept = false - # Is self transformed to a other production for the AST - # FIXME: cleanup AST - var spe: nullable Production = null is writable + # Is self present as a distinct AST class + fun is_ast: Bool do return parent_production == self + + # The production AST where non transformed alternative are attached to. + # If no such production exists, return null + fun parent_production: nullable Production + do + var res = ast_type.element + if not res isa Production then return null # it is a token + if ast_type.is_plain then return res + return null # is is nullable and/or array + end + # Is self contains only a single alternative (then no need for a abstract production class in the AST) # FIXME cleanup AST var altone = false is writable - # The cname of the class in the AST - # FIXME: cleanup AST - redef fun acname do - if spe != null then return spe.acname - return super - end - # Is the production nullable var is_nullable = false @@ -553,6 +561,64 @@ class Production end end +# static types of AST elements (AST productions and tokens) +class ASTType + var element: Element + var is_nullable: Bool = false + var is_array: Bool = false + + fun is_plain: Bool + do + return not is_nullable and not is_array + end + + redef fun to_s + do + var res = element.name + if is_nullable then + if is_array then + return "{res}*" + else + return "{res}?" + end + else + if is_array then + return "{res}+" + else + return res + end + end + end + + fun as_nullable: ASTType + do + if is_nullable then return self + var res = new ASTType(element) + res.is_nullable = true + res.is_array = is_array + return res + end + fun as_array: ASTType + do + if is_array then return self + var res = new ASTType(element) + res.is_nullable = is_nullable + res.is_array = true + return res + end + fun to_nit: String + do + var res = "N" + element.cname + if is_array then + res = "Nodes[{res}]" + end + if is_nullable then + res = "nullable {res}" + end + return res + end +end + # An alternative of a production class Alternative # The production @@ -664,11 +730,11 @@ abstract class Element var name: String redef fun to_s do return name + var ast_type: ASTType = new ASTType(self) is writable + # An example of a string fun sample_to_s: String is abstract - private var acname_cache: nullable String = null - # The mangled name of the element var cname: String is noinit, writable @@ -676,19 +742,6 @@ abstract class Element do cname = name end - - # The name of the class in the AST - fun acname: String do - var res = acname_cache - if res == null then - res = "N{cname}" - acname_cache = res - end - return res - end - - # The name of the class in the AST - fun acname=(s: String) do acname_cache = s end # A terminal element diff --git a/contrib/nitcc/src/lrautomaton.nit b/contrib/nitcc/src/lrautomaton.nit index 5b74d8e7d8..7e65f7b653 100644 --- a/contrib/nitcc/src/lrautomaton.nit +++ b/contrib/nitcc/src/lrautomaton.nit @@ -381,7 +381,7 @@ redef class Generator add "end" for t in gram.tokens do - add "redef class {t.acname}" + add "redef class {t.ast_type.to_nit}" for s in t.shifts do if not s.need_guard then continue add "\tredef fun action_s{s.number}(parser) do" @@ -484,7 +484,7 @@ redef class Generator add "\t\t# REDUCE {alt}" var i = alt.elems.length - 1 for e in alt.elems.to_a.reversed do - add "\t\tvar n{i} = parser.pop.as({e.acname})" + add "\t\tvar n{i} = parser.pop.as({e.ast_type.to_nit})" i -= 1 end @@ -520,7 +520,7 @@ redef class Generator st.add("p{cpt}") else if c isa CodeNewNodes then cpt += 1 - add "\t\tvar p{cpt} = new {c.alt.prod.acname}" + add "\t\tvar p{cpt} = new {c.alt.prod.ast_type.to_nit}" st.add("p{cpt}") else if c isa CodeAdd then var a1 = st.pop diff --git a/contrib/nitcc/src/nitcc_semantic.nit b/contrib/nitcc/src/nitcc_semantic.nit index 33e175b0b0..d9d4547097 100644 --- a/contrib/nitcc/src/nitcc_semantic.nit +++ b/contrib/nitcc/src/nitcc_semantic.nit @@ -34,6 +34,26 @@ class CollectNameVisitor # Symbol table to associate things (prods and exprs) with their name var names = new HashMap[String, Node] + fun get_element(name: String): nullable Element + do + if not names.has_key(name) then return null + var node = names[name] + if node isa Nprod then + return node.prod.as(not null) + else if node isa Nexpr then + var elem = node.token + if elem == null then + elem = new Token(name) + elem.nexpr = node + gram.tokens.add(elem) + node.token = elem + end + return elem + else + abort + end + end + # The associated grammar object # Read the result of the visit here var gram = new Gram @@ -320,7 +340,7 @@ redef class Nprod # The main production will be used for the last priority class var spe = prod prod = new Production(name + "0") - prod.spe = spe + prod.ast_type = spe.ast_type v.gram.prods.add(prod) end self.sub_prod = prod @@ -341,19 +361,8 @@ redef class Nptrans var id = children[2].as(Nid) var name = id.text - var node = v.v1.names[name] - if node isa Nprod then - v.prod.spe = node.prod.as(not null) - if v.prod.spe.spe != null then - print "Cannot transform into {name}, {name} is already transformed." - exit(1) - abort - end - else if node isa Nexpr then - print "Cannot transform into {name}, {name} is a token." - else - abort - end + var elem = v.v1.get_element(name) + v.prod.ast_type = elem.ast_type end end @@ -370,6 +379,8 @@ redef class Npriority # The associated production var prod: nullable Production + fun main_prod: nullable Production do return prod.parent_production + # The production in the with the next less priority class. # `null` if there is no priority or if the first priority class. var next: nullable Production @@ -377,14 +388,14 @@ redef class Npriority redef fun accept_collect_prod(v) do var old = v.prod assert old != null - var spe = old.spe + var spe = old.parent_production assert spe != null if is_last then prod = spe else v.pricpt -= 1 prod = new Production(spe.name + "{v.pricpt}") - prod.spe = spe + prod.ast_type = spe.ast_type v.gram.prods.add(prod.as(not null)) end next = old @@ -413,7 +424,7 @@ end redef class Npriority_left redef fun check_priority(v) do - var p = prod.spe or else prod + var p = main_prod assert p != null if v.elems.length < 2 or v.elems.first != p or v.elems.last != p then print("Error: in a Left priority class, left and right must be the production") @@ -426,7 +437,7 @@ end redef class Npriority_right redef fun check_priority(v) do - var p = prod.spe or else prod + var p = main_prod assert p != null if v.elems.length < 2 or v.elems.first != p or v.elems.last != p then print("Error: in a Right priority class, left and right must be the production") @@ -439,7 +450,7 @@ end redef class Npriority_unary redef fun check_priority(v) do - var p = prod.spe or else prod + var p = main_prod assert p != null if v.elems.length < 2 or (v.elems.first != p and v.elems.last != p) then print("Error: in a Unary priority class, left or right must be the production") @@ -473,13 +484,12 @@ redef class Nalt if pri != null then pri.check_priority(v) var prod = v.prod.as(not null) - var prodabs = prod.spe - if prodabs == null then prodabs = prod + var prodabs = prod.parent_production var name = v.altname if name == null then if v.trans then name = prod.name + "_" + prod.alts.length.to_s - else if prod.spe == null and prod.alts.is_empty and pri == null then + else if prod.is_ast and prod.alts.is_empty and pri == null then name = prod.name prod.altone = true else @@ -515,7 +525,7 @@ redef class Naltid var name = id.text v.altname = name var prod = v.prod.as(not null) - var prodabs = prod.spe + var prodabs = prod.parent_production if prodabs == null then prodabs = prod for x in prodabs.alts do if x.short_name == name then @@ -616,27 +626,12 @@ redef class Nelem_id redef fun accept_check_name_visitor(v) do var id = children.first.as(Nid) var name = id.text - if not v.v1.names.has_key(name) then + var elem = v.v1.get_element(name) + if elem == null then print "{id.position.to_s} Error: unknown name {name}" exit(1) abort end - var node = v.v1.names[name] - var elem: nullable Element - if node isa Nprod then - elem = node.prod - else if node isa Nexpr then - elem = node.token - if elem == null then - elem = new Token(name) - elem.nexpr = node - v.v1.gram.tokens.add(elem) - node.token = elem - end - else - abort - end - assert elem != null set_elem(v, id.position, elem) if v.elemname == null then v.elemname = name end diff --git a/contrib/nitcc/tests/sav/trans2.input.res b/contrib/nitcc/tests/sav/trans2.input.res new file mode 100644 index 0000000000..241d41608c --- /dev/null +++ b/contrib/nitcc/tests/sav/trans2.input.res @@ -0,0 +1,20 @@ +Start + s_0 + s_0 + s_0 + s_0 + s_0 + s_1 + b_0 + 'x'@(1:1-1:2) + b_0 + 'x'@(1:2-1:3) + c_0 + 'y'@(1:3-1:4) + c_0 + 'y'@(1:4-1:5) + b_0 + 'x'@(1:5-1:6) + c_0 + 'y'@(1:6-1:7) + Eof@(1:7-1:7)='' diff --git a/contrib/nitcc/tests/sav/trans_token.input.res b/contrib/nitcc/tests/sav/trans_token.input.res new file mode 100644 index 0000000000..1fb1aac316 --- /dev/null +++ b/contrib/nitcc/tests/sav/trans_token.input.res @@ -0,0 +1,4 @@ +Start + p + a@(1:1-1:2)='a' + Eof@(1:2-1:2)='' diff --git a/contrib/nitcc/tests/trans2.input b/contrib/nitcc/tests/trans2.input new file mode 100644 index 0000000000..eaad3280de --- /dev/null +++ b/contrib/nitcc/tests/trans2.input @@ -0,0 +1 @@ +xxyyxy \ No newline at end of file diff --git a/contrib/nitcc/tests/trans2.sablecc b/contrib/nitcc/tests/trans2.sablecc new file mode 100644 index 0000000000..8c1ee10458 --- /dev/null +++ b/contrib/nitcc/tests/trans2.sablecc @@ -0,0 +1,8 @@ +Grammar trans; + +Parser + +s = s b | b; +a = ; +b {-> a} = 'x' | c {->}; +c {-> a} = 'y'; diff --git a/contrib/nitcc/tests/trans_token.input b/contrib/nitcc/tests/trans_token.input new file mode 100644 index 0000000000..2e65efe2a1 --- /dev/null +++ b/contrib/nitcc/tests/trans_token.input @@ -0,0 +1 @@ +a \ No newline at end of file diff --git a/contrib/nitcc/tests/trans_token.sablecc b/contrib/nitcc/tests/trans_token.sablecc new file mode 100644 index 0000000000..dda16d9182 --- /dev/null +++ b/contrib/nitcc/tests/trans_token.sablecc @@ -0,0 +1,6 @@ +Lexer +a = 'a'; + +Parser +p = q; +q {-> a} = a {->};