Last active
October 27, 2023 09:13
-
-
Save AlexzPurewoko/3870f933009fc6fa61cfdb166a2ed050 to your computer and use it in GitHub Desktop.
Just a simple and small compiler for math operation. Still incomplete and needs add further operation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//////////////////////////////// FRONT - END COMPILER | |
// scan tokens | |
function scan(sourceCode) { | |
const tokens = sourceCode.split(' ') | |
return tokens | |
} | |
const INT_TOKEN = 1 | |
const OPERATION_TOKEN = 2 | |
const ADD_TOKEN = 3 | |
function parse(tokens) { | |
const parseResult = [] | |
for(let token of tokens) { | |
if (token.match(/[0-9]+/)) { | |
parseResult.push({ | |
type: INT_TOKEN, | |
value: parseInt(token) | |
}) | |
} else if (token.match(/[\+]/)) { | |
parseResult.push({ | |
type: OPERATION_TOKEN, | |
value: ADD_TOKEN | |
}) | |
} | |
// other parse .... | |
} | |
return parseResult | |
} | |
function analyzeSemantics(parsedTokens) { | |
const OP_STACK = [] | |
for (let parsedToken of parsedTokens) { | |
const tokenType = parsedToken.type; | |
const lastOperation = OP_STACK.pop(); | |
if (lastOperation?.type === tokenType) { | |
throw Error(`Next operation must not replicate the same operation with last. Last ${describeTokenType(lastOperation)}, Next: ${describeTokenType(parsedToken)}`); | |
} | |
OP_STACK.push(parsedToken) | |
} | |
console.log('semantics is correct') | |
} | |
function describeTokenType(token) { | |
if (token.type === OPERATION_TOKEN) { | |
if (token.value === ADD_TOKEN) { | |
return '+' | |
} | |
} else if(intType === INT_TOKEN) { | |
return token.value | |
} | |
throw Error('Invalid Token!') | |
} | |
function buildSymbolTable(parsedTokens) { | |
const symbolTableResult = [] | |
const tokenStack = []; | |
let tempSymbol = {}; // operator op1 op2 | |
for(let parsedToken of parsedTokens) { | |
const lastToken = tokenStack.pop(); | |
if (parsedToken.type === OPERATION_TOKEN) { | |
tempSymbol.operator = parsedToken.value; | |
tempSymbol.op1 = lastToken?.value ?? '#'; // '#' means get from prev result or 0 | |
if (symbolTableResult.length > 0) { | |
tempSymbol.op1 = '#'; // we want to be operate with prev value | |
} | |
} | |
if (lastToken?.type === OPERATION_TOKEN) { | |
tempSymbol.op2 = parsedToken.value; | |
symbolTableResult.push(tempSymbol) | |
tempSymbol = {}; | |
} | |
tokenStack.push(parsedToken) | |
} | |
return symbolTableResult; | |
} | |
const sourceCode = '5 + 10 + 15' | |
const tokens = scan(sourceCode) | |
// console.log(tokens) | |
const parseResult = parse(tokens) | |
console.log(parseResult) | |
analyzeSemantics(parseResult) | |
const symbolTableResult = buildSymbolTable(parseResult) | |
console.log(symbolTableResult) | |
//////////////////////////////// BACK - END COMPILER | |
// we play in register r1 and r2 | |
// r1 serves as final result | |
function intermediateGeneration(symbolTable) { | |
let resultIntermediateCode = ''; | |
for(const symbol of symbolTable) { | |
const {operator, op1, op2} = symbol; | |
// if first time... | |
if (op1 === '#' && resultIntermediateCode.length === 0) { | |
resultIntermediateCode += 'MOV r1, 0\n' // for safety operation | |
} | |
if (op1 !== '#') { | |
resultIntermediateCode += `MOV r1, ${op1}\n` | |
} | |
resultIntermediateCode += `MOV r2, ${op2}\n` | |
if (operator === ADD_TOKEN) { | |
resultIntermediateCode += `ADD r1, r2\n` | |
} | |
} | |
resultIntermediateCode += `PRINT r1` | |
return resultIntermediateCode; | |
} | |
console.log(intermediateGeneration(symbolTableResult)) | |
// MOV r1, 5 | |
// MOV r2, 10 | |
// ADD r1, r2 | |
// MOV r2, 15 | |
// ADD r1, r2 | |
// PRINT r1 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment