fun parse_error
do
var token = peek_token
- print "* parse error in state {state} on token {token}"
- print " expected: {state.error_msg}"
- print " node_stack={node_stack.join(", ")}"
- print " state_stack={state_stack.join(", ")}"
- var error: Node
+ #print "* parse error in state {state} on token {token}"
+ #print " expected: {state.error_msg}"
+ #print " node_stack={node_stack.join(", ")}"
+ #print " state_stack={state_stack.join(", ")}"
+ node_stack.add(token)
+ var error: NError
if token isa NLexerError then
error = token
- token.error_tree.items.add_all(node_stack)
else
error = new NParserError
error.position = token.position
error.text = token.text
error.token = token
- error.error_tree.items.add_all(node_stack)
end
+ error.error_tree.children.add_all(node_stack)
+ error.expected = state.error_msg
node_stack.clear
node_stack.add error
stop = true
last_state = state
end
var c
+ var next
if pos >= length then
c = '\0'
+ next = null
else
- c = text[pos]
+ c = text.chars[pos]
+ next = state.trans(c)
end
- var next = state.trans(c)
if next == null then
- if last_state == null then
- var token = new NLexerError
- var position = new Position(pos_start, pos, line_start, line, col_start, col)
- token.position = position
- token.text = text.substring(pos_start, pos-pos_start+1)
- res.add token
- break
+ if pos_start < length then
+ if last_state == null then
+ var token = new NLexerError
+ var position = new Position(pos_start, pos, line_start, line, col_start, col)
+ token.position = position
+ token.text = text.substring(pos_start, pos-pos_start+1)
+ res.add token
+ break
+ end
+ var position = new Position(pos_start, pos_end, line_start, line_end, col_start, col_end)
+ var token = last_state.make_token(position, text.substring(pos_start, pos_end-pos_start+1))
+ if token != null then res.add(token)
end
- var position = new Position(pos_start, pos_end, line_start, line_end, col_start, col_end)
- var token = last_state.make_token(position, text.substring(pos_start, pos_end-pos_start+1))
- if token != null then res.add(token)
if pos >= length then
- token = new NEof
- position = new Position(pos, pos, line, line, col, col)
+ var token = new NEof
+ var position = new Position(pos, pos, line, line, col, col)
token.position = position
token.text = ""
res.add token
# The name of the node (as used in the grammar file)
fun node_name: String do return class_name
- # A point of view on the direct childrens of the node
+ # A point of view on the direct children of the node
fun children: SequenceRead[nullable Node] is abstract
+ # A point of view of a depth-first visit of all non-null children
+ var depth: Collection[Node] = new DephCollection(self)
+
# Visit all the children of the node with the visitor `v`
protected fun visit_children(v: Visitor)
do
end
end
+private class DephCollection
+ super Collection[Node]
+ var node: Node
+ redef fun iterator do return new DephIterator([node].iterator)
+end
+
+private class DephIterator
+ super Iterator[Node]
+ var stack = new List[Iterator[nullable Node]]
+
+ init(i: Iterator[nullable Node])
+ do
+ stack.add i
+ end
+
+ redef fun is_ok do return not stack.is_empty
+ redef fun item do return stack.last.item.as(not null)
+ redef fun next
+ do
+ var i = stack.last
+ stack.push i.item.children.iterator
+ i.next
+ while is_ok do
+ if not stack.last.is_ok then
+ stack.pop
+ continue
+ end
+ if stack.last.item == null then
+ stack.last.next
+ continue
+ end
+ return
+ end
+ end
+end
+
# A token produced by the lexer and used in a syntactic tree
abstract class NToken
super Node
# All the partially built tree during parsing (aka the node_stack)
var error_tree = new Nodes[Node]
+
+ # The things unexpected
+ fun unexpected: String is abstract
+
+ # The things expected (if any)
+ var expected: nullable String = null
+
+ # The error message,using `expected` and `unexpected`
+ fun message: String
+ do
+ var exp = expected
+ var res = "Unexpected {unexpected}"
+ if exp != null then res += "; is acceptable instead: {exp}"
+ return res
+ end
end
# A lexer error as a token for the unexpected characted
class NLexerError
super NError
+
+ redef fun unexpected do return "character '{text.chars.first}'"
end
# A parser error linked to a unexpected token
class NParserError
super NError
+
# The unexpected token
- var token: nullable NToken
+ var token: nullable NToken = null
+
+ redef fun unexpected
+ do
+ var res = token.node_name
+ var text = token.text
+ if not text.is_empty and res != "'{text}'" then
+ res += " '{text.escape_to_c}'"
+ end
+ return res
+ end
end
# A hogeneous sequence of node, used to represent unbounded lists (and + modifier)
class Nodes[T: Node]
super Node
- redef fun children do return items
- var items = new Array[T]
+ redef var children = new Array[T]
end
-# A production with a specific, named and statically typed childrens
+# A production with a specific, named and statically typed children
class NProd
super Node
redef var children: SequenceRead[nullable Node] = new NProdChildren(self)
var filepath = args.shift
var text
if filepath == "-" then
- text = stdin.read_all
+ text = sys.stdin.read_all
else if filepath == "-e" then
if args.is_empty then
print "Error: -e need a text"
var tpv = new TreePrinterVisitor(f)
var astdotout = "{name}.ast.dot"
if n isa NError then
+ print "Syntax error: {n.message}"
print "ERROR: {n} (see {astout} and {astdotout})"
tpv.enter_visit(n)
n = n.error_tree
else
- print "ROOT: {n} (see {astout} and {astdotout})"
+ print "ROOT: {n}; {n.depth.length} nodes (see {astout} and {astdotout})"
end
tpv.enter_visit(n)
n.to_dot(astdotout)