Skip to content

Instantly share code, notes, and snippets.

@rsalgado
Created June 14, 2019 23:08
Show Gist options
  • Save rsalgado/8a106da3d61b16ad58ab7bdd7dca3052 to your computer and use it in GitHub Desktop.
Save rsalgado/8a106da3d61b16ad58ab7bdd7dca3052 to your computer and use it in GitHub Desktop.
Small attempt at a lisp parser
/*
Small and bare-bones Lisp parser and evaluator inspired by the respective problem posed at: https://www.recurse.com/pairing-tasks.
NOTE: This was my first time, as I had no previous experience with Lisp languages and only had some vague notions of them
besides the fact that their notation is prefix-based, so this implementation might not be totally correct.
This was just for the sake of learning and experimenting. And only implements four function: +, *, list and first.
*/
function tokenize(input) {
let validTokensRegExp = /(\w+|\(|\)|\+|\*)/g;
let tokens = input.match(validTokensRegExp);
if (tokens)
return tokens;
else
return [];
}
function parse(tokens) {
if (tokens.length === 0) return null;
let token = tokens.shift();
if (token === "(") {
let result = [];
while (tokens.length > 0 && tokens[0] !== ")") {
let term = parse(tokens);
result.push(term);
}
match(tokens, ")");
return result;
}
else if (/\d+/.test(token)) return +token;
else if (/[a-z]+/.test(token)) return token;
else return token;
}
function match(tokens, expectedToken) {
if (tokens.length > 0 && tokens[0] === expectedToken)
return tokens.shift();
throw Error(`Expected ${expectedToken}`);
}
function evaluate(tree) {
if (tree instanceof Array) {
let operator = tree[0];
let operands = tree.slice(1);
return apply(operator, operands);
}
else
return tree;
}
function apply(operator, operands) {
switch (operator) {
case "+":
return operands.reduce((accum, term) => accum + evaluate(term), 0);
case "*":
return operands.reduce((accum, term) => accum * evaluate(term), 1);
case "list":
return operands.reduce((accum, term) => {
accum.push(evaluate(term));
return accum;
}, []);
case "first":
let operand = operands[0];
return evaluate(operand)[0];
default:
throw Error(`Operator "${operator}" not defined`);
}
}
function interpret(input) {
let tokens = tokenize(input);
let tree = parse(tokens);
let result = evaluate(tree);
return result;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment