| @@ -25,6 +25,10 @@ function TokenStream(input){ | |||
| return (pos < input.length) ? input[pos].col : -1; | |||
| } | |||
| function eol(){ | |||
| return (pos < input.length - 1) ? (input[pos].line !== input[pos+1].line) : true; | |||
| } | |||
| function eof(){ | |||
| return (pos >= input.length); | |||
| } | |||
| @@ -54,7 +58,7 @@ function isTokenType(type, val){ | |||
| } | |||
| function isPunc(ch){ | |||
| return isTokenType("punk", ch); | |||
| return isTokenType("punc", ch); | |||
| } | |||
| function isOpCode(ch){ | |||
| @@ -74,6 +78,63 @@ function isOp(ch){ | |||
| } | |||
| function skipPunc(ch){ | |||
| if (isPunc(ch)){ | |||
| stream.next(); | |||
| } else { | |||
| stream.die("Unexpected punctuation '" + ch + "'."); | |||
| } | |||
| } | |||
| parseDelimited(s,e,d,parser){ | |||
| let toEOL = (s === null || e === null); | |||
| let a = []; | |||
| let first = true; | |||
| if (!toEOL){skipPunc(s);} | |||
| while (!stream.eof() && ((!toEOL && isPunc(e)) || (toEOL && !stream.eol()))){ | |||
| if (first){ | |||
| first = false; | |||
| } else {skipPunk(d);} | |||
| a.push(parser()); | |||
| } | |||
| if (!toEOL){skipPunc(e);} | |||
| return a; | |||
| } | |||
| parseOpCode(){ | |||
| let val = stream.next(); | |||
| let mode = 0; // Guess between absolute and zero page. | |||
| let args = []; // TODO: Finish figuring out how to get the argument list! | |||
| if (isOp("#")){ | |||
| stream.next(); | |||
| mode = 1; // Immediate | |||
| } else if (isPunc("(")){ | |||
| mode = 2; // Indirect | |||
| // TODO: Use parseDelimited() | |||
| } | |||
| return { | |||
| type: "opcode", | |||
| val: val, | |||
| args: args, | |||
| mode: mode | |||
| }; | |||
| } | |||
| parseAtom(){ | |||
| if (isPunc("(")){ | |||
| stream.next(); | |||
| let exp = parseExpression(); | |||
| if (isPunc(")")){ | |||
| stream.next(); | |||
| return exp; | |||
| } | |||
| } else if (isOpCode()){ | |||
| return parseOpCode(); | |||
| } | |||
| } | |||
| parse(tokens){ | |||
| let p = { | |||