瀏覽代碼

Parse coming along

master
Bryan Miller 5 年之前
父節點
當前提交
58201c6cf6
共有 1 個文件被更改,包括 105 次插入19 次删除
  1. +105
    -19
      src/MOS/6502/assembler/parser.js

+ 105
- 19
src/MOS/6502/assembler/parser.js 查看文件

@@ -33,7 +33,7 @@ function TokenStream(input){
}

function eol(){
return (pos < input.length - 1) ? (input[pos].line !== input[pos+1].line) : true;
return (pos > 0) ? (input[pos-1].line !== input[pos].line) : true;
}

function eof(){
@@ -49,6 +49,7 @@ function TokenStream(input){
next: next,
line: line,
col: col,
eol: eol,
eof, eof,
die: die
};
@@ -88,6 +89,13 @@ function skipPunc(ch){
}


function skipDirective(ch){
if (!isDirective(ch))
stream.die("Unexpected directive '" + ch + "'.");
stream.next();
}


function parseDelimited(s,e,d,parser){
let toEOL = (s === null || e === null);
let a = [];
@@ -96,7 +104,7 @@ function parseDelimited(s,e,d,parser){
while (!stream.eof() && ((!toEOL && isPunc(e)) || (toEOL && !stream.eol()))){
if (first){
first = false;
} else {skipPunk(d);}
} else {skipPunc(d);}
a.push(parser());
}
if (!toEOL){skipPunc(e);}
@@ -104,16 +112,65 @@ function parseDelimited(s,e,d,parser){
}

function parseByteDirective(){
let line = stream.line();
let col = stream.col();
stream.next();
return {
type: "directive",
op: ".byte",
args: parseDelimited(null, null, ",", parseExpression);
args: parseDelimited(null, null, ",", parseExpression),
line: line,
col: col
}
}


function parseElseIfDirective(){
skipDirective(".elseif");
let cond = parseExpression();
skipDirective(".then");
let then = parseBlock([".else", ".elif", ".endif"]);
let f = {
type: "directive",
op: "if",
cond: cond,
then: then
}
if (isDirective(".elif")){
f["else"] = parseElseIfDirective();
} else if (isDirective(".else")){
f["else"] = parseBlock([".endif"]);
} else if(!isDirective(".endif")){
stream.die("Expected '.endif' Directive.");
}
return f;
}


function parseIfDirective(){
skipDirective(".if");
let cond = parseExpression();
skipDirective(".then");
let then = parseExpression();
let f = {
type: "directive",
op: "if",
cond: cond,
then: then
};
if (isDirective(".elif")){
f["else"] = parseElseIfDirective();
} else if (isDirective(".else")){
f["else"] = parseBlock([".endif"]);
}
skipDirective(".endif");
return f;
}


function parseOpCode(){
let line = stream.line();
let col = stream.col();
let val = stream.next();
let mode = 0; // Guess between absolute and zero page.
if (isOp("#")){
@@ -124,9 +181,11 @@ function parseOpCode(){
}
return {
type: "opcode",
val: val,
op: val,
args: parseDelimited(null, null, ",", parseExpression),
mode: mode
mode: mode,
line: line,
col: col
};
}

@@ -140,20 +199,22 @@ function parseAtom(){
}
} else if (isOpCode()){
return parseOpCode();
} else if (isDirective(".byte")){
} else if (isDirective(".if")){
return parseIfDirective();
} else if (isDirective(".bytes")){
return parseByteDirective();
}

let tok = stream.next();
if (tok.type === "number" || tok.type === "string" || tok.type === "label")
return tok;
stream.die("Unexpected token " + tok);
stream.die("Unexpected token {type:" + tok.type + ", val:'" + tok.val + "'}.");
}


function parseExpression(){
maybeCall(function(){
return maybeBinary(parseAtom, 0);
return maybeCall(function(){
return maybeBinary(parseAtom(), 0);
});
}

@@ -161,7 +222,7 @@ function parseCall(func){
return {
type: "call",
func: func,
args: parseDelimited("(", ")", ",", parseExpression);
args: parseDelimited("(", ")", ",", parseExpression)
};
}

@@ -180,31 +241,56 @@ function maybeBinary(left, pres){
type: (tok.val === "=") ? "assign" : "binary",
op: tok.val,
left: left,
right: maybeBinary(parseAtom(), cpres)
right: maybeBinary(parseAtom(), cpres),
line: tok.line,
col: tok.col
}, pres);
}
}
return left;
}

function parse(tokens){
let p = {
type: "prog",
expressions: [];
};
stream = TokenStream(tokens);
function parseBlock(bed){
let exp = [];
let isBlockEnd = (t) => {
return (bed && t.type === 'directive' && bed.indexOf(t.val) >= 0);
}
while (!stream.eof()){
if (isBlockEnd(stream.peek()))
break;
let e = parseExpression();
if (e.type === "label"){
e = {
type: "assign",
op: "=",
left: e,
right: "*" // To designate "current program counter".
right: "*", // To designate "current program counter".
line: e.line,
col: e.col
}
}
p.expressions.push(e);
exp.push(e);
if (!stream.eol())
stream.die("Expected End of Line.");
}
return exp;
}

function parseProg(ed){
let line = stream.line();
let col = stream.col();
return {
type: "prog",
expressions: parseBlock(),
line: line,
col: col
};
}

function parse(tokens){
stream = TokenStream(tokens);
let p = parseProg();
stream = null;
return p;
}

Loading…
取消
儲存