# Build the NFA automaton
for t in gram.tokens do
- var nexpr = t.nexpr
- var nfa2
- if nexpr == null then
- nfa2 = new Automaton.epsilon
- for c in t.text.as(not null) do
- nfa2.concat(new Automaton.atom(c.ascii))
- end
- else
- nfa2 = nexpr.build_nfa
+ var nfa2 = t.build_nfa
+ nfa2.tag_accept(t)
+ nfa.absorb(nfa2)
+ end
+
+ if not v2.ignoreds.is_empty then
+ var ign = new Token("Ignored")
+ var nfa2 = new Automaton.empty
+ for t in v2.ignoreds do
+ assert t isa Token
+ var nfa3 = t.build_nfa
+ nfa2.alternate(nfa3)
end
- nfa.states.add_all nfa2.states
- nfa.start.add_trans(nfa2.start, null)
- for s in nfa2.accept do nfa.add_tag(s, t)
- nfa.accept.add_all nfa2.accept
+ nfa2.tag_accept(ign)
+ nfa.absorb(nfa2)
end
+
end
redef fun visit(n) do n.accept_collect_prod(self)
# Is the alternative transformed, for the alternative
var trans = false
+ # Known ignored tokens
+ var ignoreds = new Array[Element]
+
# Known rejected tokens
- var rejecteds = new Array[Token]
+ var rejecteds = new Array[Element]
# Pool of elements that are modified with + (reuse them!)
private var plusizes = new HashMap[Element, Production]
redef fun accept_collect_prod(v) do
var id = children.first.as(Nid)
var name = id.text
+ if v.names.has_key(name) then
+ print "{id.position.to_s} Error {name} already defined."
+ exit(1)
+ end
v.names[name] = self
self.name = name
end
var id = children.first.as(Nid)
var name = id.text
if not v.v1.names.has_key(name) then
- print "{id.position} Error: unknown name {name}"
+ print "{id.position.to_s} Error: unknown name {name}"
exit(1)
abort
end
var node = v.v1.names[name]
if node isa Nprod then
- print "{id.position} Error: cannot use production {name} in a regular expression"
+ print "{id.position.to_s} Error: cannot use production {name} in a regular expression"
exit(1)
abort
else if not node isa Nexpr then
end
redef class Nign
- # The named element
- var elem: nullable Element
-
redef fun accept_check_name_visitor(v) do
- var id = children[1].as(Nid)
- var name = id.text
- if not v.v1.names.has_key(name) then
- print "{id.position} Error: unknown name {name}"
- exit(1)
- abort
- end
- var node = v.v1.names[name]
- var elem: nullable Element
- if node isa Nprod then
- print "{id.position} Error: cannot ignore a production"
- exit(1)
- abort
- else if node isa Nexpr then
- elem = node.token
- if elem == null then
- elem = new Token("Ignored")
- elem.nexpr = node
- v.v1.gram.tokens.add(elem)
- node.token = elem
+ # Add elements to the ignored list
+ v.elems = v.ignoreds
+ super
+ for e in v.elems do
+ if e isa Production then
+ print "Error: cannot ignore {e}, it is a production"
+ exit(1)
+ abort
+ else if e isa Token then
+ # The token was build and registered during the visit
+ # So, unregister then, the bit Ignred token will be build later
+ v.v1.gram.tokens.remove(e)
+ else
+ abort
end
- else
- abort
end
- self.elem = elem
end
end
redef class Nrej
redef fun accept_check_name_visitor(v) do
- v.elems = new Array[Element]
+ # Add elements to the rejected list
+ v.elems = v.rejecteds
super
for e in v.elems do
if e isa Production then
abort
else if e isa Token then
# The token was build and registered during the visit
- # Just add it to the rejected list
- v.rejecteds.add(e)
else
abort
end
redef fun accept_collect_prod(v) do
var id = children.first.as(Nid)
var name = id.text
+ if v.names.has_key(name) then
+ print "{id.position.to_s} Error {name} already defined."
+ exit(1)
+ end
v.names[name] = self
v.nprods.add(self)
prod = new Production(name)
redef class Natrans
redef fun accept_check_name_visitor(v) do
- var id = children[2].as(Nid)
- var name = id.text
-
v.trans = true
end
end
+redef class Alternative
+ var short_name: nullable String
+end
+
redef class Nalt
# The associated alternative
var alt: nullable Alternative
name = prodabs.name + "_" + name
end
var alt = prod.new_alt2(name, v.elems)
+ alt.short_name = v.altname
alt.elems_names.add_all(v.elems_names)
self.alt = alt
if v.trans then
var id = children[1].as(Nid)
var name = id.text
v.altname = name
+ var prod = v.prod.as(not null)
+ var prodabs = prod.spe
+ if prodabs == null then prodabs = prod
+ for x in prodabs.alts do
+ if x.short_name == name then
+ print "{id.position.to_s} Error: already an alternative named {name}"
+ exit(1)
+ end
+ end
end
end
var elem: nullable Element
# Set the element and check things
- fun set_elem(v: CheckNameVisitor, pos: nullable Position, elem: Element)
+ private fun set_elem(v: CheckNameVisitor, pos: nullable Position, elem: Element)
do
assert self.elem == null
self.elem = elem
- v.elems.push(elem)
- if elem isa Token and v.rejecteds.has(elem) then
- if pos != null then
- print "{pos} Error: {elem.name} is already a rejected token."
- else
- print "Error: {elem.name} is already a rejected token."
+ if elem isa Token then
+ if v.ignoreds.has(elem) then
+ if pos != null then
+ print "{pos} Error: {elem.name} is already an ignored token."
+ else
+ print "Error: {elem.name} is already an ignored token."
+ end
+ exit(1)
+ end
+ if v.rejecteds.has(elem) then
+ if pos != null then
+ print "{pos} Error: {elem.name} is already a rejected token."
+ else
+ print "Error: {elem.name} is already a rejected token."
+ end
+ exit(1)
end
- exit(1)
end
-
+ v.elems.push(elem)
end
-
end
redef class Token
var nexpr: nullable Nexpr
# The associated text (if any, ie defined in the parser part)
var text: nullable String
+
+ # Build a NFA according to nexpr or text
+ # Does not tag it!
+ fun build_nfa: Automaton
+ do
+ var nexpr = self.nexpr
+ if nexpr != null then
+ assert self.text == null
+ return nexpr.build_nfa
+ end
+ var text = self.text
+ if text != null then
+ var nfa = new Automaton.epsilon
+ for c in text.chars do
+ nfa.concat(new Automaton.atom(c.ascii))
+ end
+ return nfa
+ end
+ abort
+ end
end
redef class Nnelem
do
var id = children[1].as(Nid)
var name = id.text
+ for n2 in v.elems_names do
+ if name == n2 then
+ print "{id.position.to_s} Error: already an element named {name}."
+ exit(1)
+ end
+ end
v.elemname = name
end
end
var id = children.first.as(Nid)
var name = id.text
if not v.v1.names.has_key(name) then
- print "{id.position} Error: unknown name {name}"
+ print "{id.position.to_s} Error: unknown name {name}"
exit(1)
abort
end
redef class Nelem_str
redef fun accept_check_name_visitor(v) do
- var str = children.first.as(Nstr)
+ var str = children.first.children.first.as(NToken)
var text = str.value
var name = str.text
var elem: nullable Element