Skip to content

Instantly share code, notes, and snippets.

@AlexzPurewoko
Last active October 27, 2023 09:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AlexzPurewoko/3870f933009fc6fa61cfdb166a2ed050 to your computer and use it in GitHub Desktop.
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
//////////////////////////////// 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