abstract class Parser
# The list of tokens
# FIXME: provide something better, like a lexer?
- var tokens = new List[NToken]
+ var tokens = new CircularArray[NToken]
# Look at the next token
# Used by generated parsers
#print " expected: {state.error_msg}"
#print " node_stack={node_stack.join(", ")}"
#print " state_stack={state_stack.join(", ")}"
- node_stack.add(token)
+ node_stack.push(token)
var error: NError
if token isa NLexerError then
error = token
protected fun start_state: DFAState is abstract
# Lexize a stream of characters and return a sequence of tokens
- fun lex: List[NToken]
+ fun lex: CircularArray[NToken]
do
- var res = new List[NToken]
+ var res = new CircularArray[NToken]
var state = start_state
var pos = 0
var pos_start = 0
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
+ res.push 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)
+ if not last_state.is_ignored then
+ var position = new Position(pos_start, pos_end, line_start, line_end, col_start, col_end)
+ var token = last_state.make_token(position, text)
+ if token != null then res.push(token)
+ end
end
if pos >= length then
var token = new NEof
var position = new Position(pos, pos, line, line, col, col)
token.position = position
token.text = ""
- res.add token
+ res.push token
break
end
state = start_state
interface DFAState
fun is_accept: Bool do return false
fun trans(c: Char): nullable DFAState do return null
- fun make_token(position: Position, text: String): nullable NToken is abstract
+ fun make_token(position: Position, source: String): nullable NToken is abstract
+ fun is_ignored: Bool do return false
end
###
# Print a node (using to_s) on a line and recustively each children indented (with two spaces)
class TreePrinterVisitor
super Visitor
- var writer: OStream
+ var writer: Writer
private var indent = 0
- init(writer: OStream) do self.writer = writer
redef fun visit(n)
do
for i in [0..indent[ do writer.write(" ")
var line_end: Int
var col_start: Int
var col_end: Int
+
redef fun to_s do return "{line_start}:{col_start}-{line_end}:{col_end}"
+
+ # Extract the content from the given source
+ fun extract(source: String): String
+ do
+ return source.substring(pos_start, pos_end-pos_start+1)
+ end
+
+ # Get the lines covered by `self` and underline the target columns.
+ #
+ # This is useful for pretty printing errors or debug the output
+ #
+ # ~~~
+ # var src = "var Foo = new Array[Int]"
+ # var pos = new Position(0,0, 1, 1, 5, 8)
+ #
+ # assert pos.underline(src) == """
+ # var Foo = new Array[Int]
+ # ^^^"""
+ # ~~~
+ fun underline(source: Text): String
+ do
+ var res = new FlatBuffer
+
+ # All the concerned lines
+ var lines = source.split("\n")
+ for line in [line_start..line_end] do
+ res.append lines[line-1]
+ res.append "\n"
+ end
+
+ # Cover all columns, no matter their lines
+ var col_start = col_start.min(col_end)
+ var col_end = self.col_start.max(col_end)
+
+ # " ^^^^"
+ var ptr = " "*(col_start-1).max(0) + "^"*(col_end-col_start)
+ res.append ptr
+
+ return res.to_s
+ end
end
# A node of a syntactic tree
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)
+ var depth: Collection[Node] = new DephCollection(self) is lazy
# Visit all the children of the node with the visitor `v`
protected fun visit_children(v: Visitor)
# Produce a graphiz file for the syntaxtic tree rooted at `self`.
fun to_dot(filepath: String)
do
- var f = new OFStream.open(filepath)
+ var f = new FileWriter.open(filepath)
f.write("digraph g \{\n")
f.write("rankdir=BT;\n")
f.close
end
- private fun to_dot_visitor(f: OStream, a: Array[NToken])
+ private fun to_dot_visitor(f: Writer, a: Array[NToken])
do
f.write("n{object_id} [label=\"{node_name}\"];\n")
for x in children do
private class DephIterator
super Iterator[Node]
- var stack = new List[Iterator[nullable Node]]
- init(i: Iterator[nullable Node])
- do
- stack.add i
+ var stack = new Array[Iterator[nullable Node]]
+
+ init(i: Iterator[nullable Node]) is old_style_init do
+ stack.push i
end
redef fun is_ok do return not stack.is_empty
end
# A production with a specific, named and statically typed children
-class NProd
+abstract class NProd
super Node
redef var children: SequenceRead[nullable Node] = new NProdChildren(self)
end
text = args.shift
else
- var f = new IFStream.open(filepath)
+ var f = new FileReader.open(filepath)
text = f.read_all
f.close
end
var tokout = "{name}.tokens.out"
print "TOKEN: {tokens.length} tokens (see {tokout})"
- var f = new OFStream.open(tokout)
+ var f = new FileWriter.open(tokout)
for t in tokens do
f.write "{t.to_s}\n"
end
var n = p.parse
var astout = "{name}.ast.out"
- f = new OFStream.open(astout)
+ f = new FileWriter.open(astout)
var tpv = new TreePrinterVisitor(f)
var astdotout = "{name}.ast.dot"
if n isa NError then