|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function TokenStream(input){ |
|
|
|
|
|
var pos = 0; |
|
|
|
|
|
|
|
|
|
|
|
function peek(){ |
|
|
|
|
|
return input[pos]; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function next(){ |
|
|
|
|
|
let v = input[pos]; |
|
|
|
|
|
pos += 1; |
|
|
|
|
|
return v; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function line(){ |
|
|
|
|
|
return (pos < input.length) ? input[pos].line : -1; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function col(){ |
|
|
|
|
|
return (pos < input.length) ? input[pos].col : -1; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function eof(){ |
|
|
|
|
|
return (pos >= input.length); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function die(msg){ |
|
|
|
|
|
throw new Error(msg + " Line: " + input[pos].line + ", Col: " + input[pos].col); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return { |
|
|
|
|
|
peek: peek, |
|
|
|
|
|
next: next, |
|
|
|
|
|
line: line, |
|
|
|
|
|
col: col, |
|
|
|
|
|
eof, eof, |
|
|
|
|
|
die: die |
|
|
|
|
|
}; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var stream = null; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
parseDirective(){ |
|
|
|
|
|
let d = stream.next(); |
|
|
|
|
|
let args = []; |
|
|
|
|
|
while (stream.peek().line === d.line){ |
|
|
|
|
|
let a = stream.next(); |
|
|
|
|
|
switch(a.type){ |
|
|
|
|
|
case "number": |
|
|
|
|
|
// TODO: Check if math ops are called. |
|
|
|
|
|
case "string": |
|
|
|
|
|
args.push(a); |
|
|
|
|
|
break; |
|
|
|
|
|
case "label": |
|
|
|
|
|
args.push({ |
|
|
|
|
|
type: "var", |
|
|
|
|
|
val: a.val, |
|
|
|
|
|
line: a.line, |
|
|
|
|
|
col: a.col |
|
|
|
|
|
}); |
|
|
|
|
|
break; |
|
|
|
|
|
case "punc": |
|
|
|
|
|
// Ignore punctuations! |
|
|
|
|
|
break; |
|
|
|
|
|
default: |
|
|
|
|
|
stream.die("Invalid token '" + a.type + "'."); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return { |
|
|
|
|
|
type: 'directive', |
|
|
|
|
|
args: args, |
|
|
|
|
|
line: d.line, |
|
|
|
|
|
col: d.col |
|
|
|
|
|
}; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
parseExpression(){ |
|
|
|
|
|
o = stream.peek(); |
|
|
|
|
|
if (o.type === 'directive'){ |
|
|
|
|
|
return parseDirective(); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
parse(tokens){ |
|
|
|
|
|
let p = { |
|
|
|
|
|
type: "prog", |
|
|
|
|
|
expressions: []; |
|
|
|
|
|
}; |
|
|
|
|
|
stream = TokenStream(tokens); |
|
|
|
|
|
while (!stream.eof()){ |
|
|
|
|
|
p.expressions.push(parseExpression()); |
|
|
|
|
|
} |
|
|
|
|
|
stream = null; |
|
|
|
|
|
return p; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
module.exports = Object.freeze({ |
|
|
|
|
|
parse: parse |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|