Browse Source

More buildout of the parser

master
Bryan Miller 5 years ago
parent
commit
4e64570f32
1 changed files with 78 additions and 18 deletions
  1. +78
    -18
      src/MOS/6502/assembler/parser.js

+ 78
- 18
src/MOS/6502/assembler/parser.js View File

const OP = require('./op.js'); const OP = require('./op.js');


const PRECEDENCE = {
"#": 0, // Precedence 0 should be ignored!
"=": 1,
"<":7, "<=":7, ">":7, ">=":7, "==":7, "!=":7,
"+": 10, "-": 10,
"*": 20, "/": 20
};


function TokenStream(input){ function TokenStream(input){
var pos = 0; var pos = 0;


function isTokenType(type, val){ function isTokenType(type, val){
let t = stream.peek(); let t = stream.peek();
if (t !== null && t.type === type){
if (!val || t.val === val)
return true;
}
return false;
return (t && t.type === type && (!val || t.val === val) && t);
} }


function isPunc(ch){ function isPunc(ch){




function skipPunc(ch){ function skipPunc(ch){
if (isPunc(ch)){
stream.next();
} else {
if (!isPunc(ch))
stream.die("Unexpected punctuation '" + ch + "'."); stream.die("Unexpected punctuation '" + ch + "'.");
}
stream.next();
} }




parseDelimited(s,e,d,parser){
function parseDelimited(s,e,d,parser){
let toEOL = (s === null || e === null); let toEOL = (s === null || e === null);
let a = []; let a = [];
let first = true; let first = true;
return a; return a;
} }


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



parseOpCode(){
function parseOpCode(){
let val = stream.next(); let val = stream.next();
let mode = 0; // Guess between absolute and zero page. let mode = 0; // Guess between absolute and zero page.
let args = []; // TODO: Finish figuring out how to get the argument list!
if (isOp("#")){ if (isOp("#")){
stream.next(); stream.next();
mode = 1; // Immediate mode = 1; // Immediate
} else if (isPunc("(")){ } else if (isPunc("(")){
mode = 2; // Indirect mode = 2; // Indirect
// TODO: Use parseDelimited()
}
}
return { return {
type: "opcode", type: "opcode",
val: val, val: val,
args: args,
args: parseDelimited(null, null, ",", parseExpression),
mode: mode mode: mode
}; };
} }


parseAtom(){
function parseAtom(){
if (isPunc("(")){ if (isPunc("(")){
stream.next(); stream.next();
let exp = parseExpression(); let exp = parseExpression();
} }
} else if (isOpCode()){ } else if (isOpCode()){
return parseOpCode(); return parseOpCode();
} else if (isDirective(".byte")){
return parseByteDirective();
} }

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




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

function parseCall(func){
return {
type: "call",
func: func,
args: parseDelimited("(", ")", ",", parseExpression);
};
}

function maybeCall(expr){
expr = expr();
return (isOp("(")) ? parseCall(expr) : expr;
}

function maybeBinary(left, pres){
let tok = isOp();
if (tok){
let cpres = PRECEDENCE[tok.val];
if (cpres > pres){
stream.next();
return maybeBinary({
type: (tok.val === "=") ? "assign" : "binary",
op: tok.val,
left: left,
right: maybeBinary(parseAtom(), cpres)
}, pres);
}
}
return left;
}

function parse(tokens){
let p = { let p = {
type: "prog", type: "prog",
expressions: []; expressions: [];
}; };
stream = TokenStream(tokens); stream = TokenStream(tokens);
while (!stream.eof()){ while (!stream.eof()){
p.expressions.push(parseExpression());
let e = parseExpression();
if (e.type === "label"){
e = {
type: "assign",
op: "=",
left: e,
right: "*" // To designate "current program counter".
}
}
p.expressions.push(e);
} }
stream = null; stream = null;
return p; return p;

Loading…
Cancel
Save