Skip to content

Instantly share code, notes, and snippets.

@kleczkowski
Created November 26, 2018 22:38
Show Gist options
  • Save kleczkowski/52a3ee350317b545d8d6c7324e325790 to your computer and use it in GitHub Desktop.
Save kleczkowski/52a3ee350317b545d8d6c7324e325790 to your computer and use it in GitHub Desktop.
grammar SimpleImperativeLanguage;
@lexer::header {
package com.github.repaj.glang;
}
@parser::header {
package com.github.repaj.glang;
import java.lang.*;
import com.github.repaj.glang.ir.*;
import com.github.repaj.glang.ir.symtab.*;
import com.github.repaj.glang.report.*;
}
@parser::members {
private SymbolTable table;
private ErrorLogger log;
}
program
returns [BasicBlock entry]
: 'DECLARE' decl* 'IN' stmts 'END' EOF
{
$entry = $stmts.code;
$stmts.last.add(new Halt());
}
;
stmts
returns [BasicBlock code, BasicBlock last]
locals [BasicBlock recent]
: hd=stmt
{
$code = $hd.code;
$last = $hd.last;
}
(stmt
{
$last.meld($stmt.code);
$last = $stmt.last;
}
)*
;
stmt
returns [BasicBlock code, BasicBlock last]
: assignStmt ';'
{
$code = $assignStmt.code;
$last = $assignStmt.last;
}
| ifStmt
{
$code = $ifStmt.code;
$last = $ifStmt.last;
}
| whileStmt
{
$code = $whileStmt.code;
$last = $whileStmt.last;
}
| doWhileStmt
{
$code = $doWhileStmt.code;
$last = $doWhileStmt.last;
}
| forStmt
{
$code = $forStmt.code;
$last = $forStmt.last;
}
| readStmt ';'
{
$code = $readStmt.code;
$last = $readStmt.last;
}
| writeStmt ';'
{
$code = $writeStmt.code;
$last = $writeStmt.last;
}
;
assignStmt
returns [BasicBlock code, BasicBlock last]
: variableSymbol ':=' expr
{
$last = $code = new BasicBlock();
$code.addAll($expr.code);
$code.add(new StoreVariable($variableSymbol.info, $expr.place));
}
| arraySymbol '(' arrayIdx ')' ':=' expr
{
$last = $code = new BasicBlock();
$code.addAll($expr.code);
$code.addAll($arrayIdx.code);
$code.add(new StoreArray($arraySymbol.info, $arrayIdx.place, $expr.place));
}
;
readStmt
returns [BasicBlock code, BasicBlock last]
: 'READ' variableSymbol
{
$last = $code = new BasicBlock();
$code.add(new ReadVariable($variableSymbol.info));
}
| 'READ' arraySymbol '(' arrayIdx ')'
{
$last = $code = new BasicBlock();
$code.addAll($arrayIdx.code);
$code.add(new ReadArray($arraySymbol.info, $arrayIdx.place));
}
;
writeStmt
returns [BasicBlock code, BasicBlock last]
: 'WRITE' value
{
$last = $code = new BasicBlock();
$code.addAll($value.code);
$code.add(new Write($value.place));
}
;
ifStmt
returns [BasicBlock code, BasicBlock last]
: 'IF' condition 'THEN' ifTrue=stmts ('ELSE' ifFalse=stmts)? 'ENDIF'
{
$code = new BasicBlock();
$last = new BasicBlock();
$code.addAll($condition.code);
if ($ifFalse.ctx != null) {
$code.add(new JumpIf($condition.place, $ifTrue.code, $ifFalse.code));
$code.addSuccessor($ifTrue.code);
$code.addSuccessor($ifFalse.code);
$ifTrue.last.add(new Jump($last));
$ifTrue.last.addSuccessor($last);
$ifFalse.last.add(new Jump($last));
$ifFalse.last.addSuccessor($last);
} else {
$code.add(new JumpIf($condition.place, $ifTrue.code, $last));
$code.addSuccessor($ifTrue.code);
$code.addSuccessor($last);
$ifTrue.last.add(new Jump($last));
$ifTrue.last.addSuccessor($last);
}
}
;
whileStmt
returns [BasicBlock code, BasicBlock last]
: 'WHILE' condition 'DO' body=stmts 'ENDWHILE'
{
$code = new BasicBlock();
$last = new BasicBlock();
$code.addAll($condition.code);
$code.add(new JumpIf($condition.place, $body.code, $last));
$code.addSuccessor($body.code);
$code.addSuccessor($last);
$body.last.add(new Jump($code));
$body.last.addSuccessor($code);
}
;
doWhileStmt
returns [BasicBlock code, BasicBlock last]
: 'DO' body=stmts 'WHILE' condition 'ENDDO'
{
$code = $body.code;
$last = new BasicBlock();
$body.last.addAll($condition.code);
$body.last.add(new JumpIf($condition.place, $body.code, $last));
$body.last.addSuccessor($body.code);
$body.last.addSuccessor($last);
}
;
forStmt
returns [BasicBlock code, BasicBlock last]
locals [Insturction ld, Instruction tmp1]
: 'FOR' forIterator 'DO' body=stmts 'ENDFOR'
{
$code = $forIterator.code;
$last = new BasicBlock();
$forIterator.cmpCode.add(new JumpIf($forIterator.cmp, $body.code, $last));
$forIterator.cmpCode.addSuccessor($body.code);
$forIterator.cmpCode.addSuccessor($last);
$body.last.add($ld = new LoadVariable($forIterator.info));
if (!$forIterator.downTo) {
$body.last.add($tmp1 = new Inc($ld));
} else {
$body.last.add($tmp1 = new Dec($ld));
}
$body.last.add(new StoreVariable($ld, $tmp1));
$body.last.add(new Jump($forIterator.cmpCode));
$body.last.addSuccessor($forIterator.cmpCode);
table = table.exitContext();
}
;
forIterator
returns [BasicBlock code, BasicBlock cmpCode, Instruction cmp, VariableSymbolInfo info, boolean downTo]
: {
table = table.enterContext();
}
variableDecl[true]
forIteratorRange[$variableDecl.info]
{
$info = $variableDecl.info;
$downTo = $forIteratorRange.downTo;
$code = $forIteratorRange.code;
$cmpCode = $forIteratorRange.last;
$cmp = $forIteratorRange.cmp;
}
;
forIteratorRange [VariableSymbolInfo info]
returns [BasicBlock code, Instruction cmp, BasicBlock last, boolean downTo]
locals [Instruction ld]
: 'FROM' low=value ('TO' { $downTo = false; } | 'DOWNTO' { $downTo = true; }) hi=value
{
$code = new BasicBlock();
$last = new BasicBlock();
$code.addAll($low.code);
$code.addAll($hi.code);
if (!$downTo) {
$code.add(new StoreVariable($info, $low.place));
$code.add(new Jump($last));
$code.addSuccessor($last);
$last.add($ld = new LoadVariable($info));
$last.add($cmp = new Le($ld, $hi.place));
} else {
$code.add(new StoreVariable($info, $hi.place));
$code.add(new Jump($last));
$code.addSuccessor($last);
$last.add($ld = new LoadVariable($info));
$last.add($cmp = new Ge($ld, $low.place));
}
}
;
expr
returns [Instruction place, BasicBlock code]
: l=value '+' r=value
{
$code = new BasicBlock();
$code.addAll($l.code);
$code.addAll($r.code);
$code.add($place = new Add($l.place, $r.place));
}
| l=value '-' r=value
{
$code = new BasicBlock();
$code.addAll($l.code);
$code.addAll($r.code);
$code.add($place = new Sub($l.place, $r.place));
}
| l=value '*' r=value
{
$code = new BasicBlock();
$code.addAll($l.code);
$code.addAll($r.code);
$code.add($place = new Mul($l.place, $r.place));
}
| l=value '/' r=value
{
$code = new BasicBlock();
$code.addAll($l.code);
$code.addAll($r.code);
$code.add($place = new Div($l.place, $r.place));
}
| l=value '%' r=value
{
$code = new BasicBlock();
$code.addAll($l.code);
$code.addAll($r.code);
$code.add($place = new Mod($l.place, $r.place));
}
| value
{
$place = $value.place;
$code = $value.code;
}
;
condition
returns [Instruction place, BasicBlock code]
: l=value '=' r=value
{
$code = new BasicBlock();
$code.addAll($l.code);
$code.addAll($r.code);
$code.add($place = new Eq($l.place, $r.place));
}
| l=value '!=' r=value
{
$code = new BasicBlock();
$code.addAll($l.code);
$code.addAll($r.code);
$code.add($place = new Ne($l.place, $r.place));
}
| l=value '<=' r=value
{
$code = new BasicBlock();
$code.addAll($l.code);
$code.addAll($r.code);
$code.add($place = new Le($l.place, $r.place));
}
| l=value '>=' r=value
{
$code = new BasicBlock();
$code.addAll($l.code);
$code.addAll($r.code);
$code.add($place = new Ge($l.place, $r.place));
}
| l=value '<' r=value
{
$code = new BasicBlock();
$code.addAll($l.code);
$code.addAll($r.code);
$code.add($place = new Lt($l.place, $r.place));
}
| l=value '>' r=value
{
$code = new BasicBlock();
$code.addAll($l.code);
$code.addAll($r.code);
$code.add($place = new Gt($l.place, $r.place));
}
;
value
returns [Instruction place, BasicBlock code]
: variableSymbol
{
$code = new BasicBlock();
$code.add($place = new LoadVariable($variableSymbol.info));
}
| arraySymbol '(' arrayIdx ')'
{
$code = new BasicBlock();
$code.addAll($arrayIdx.code);
$code.add($place = new LoadVariable($arraySymbol.info, $arrayIdx.place));
}
| constantSymbol
{
$code = new BasicBlock();
$code.add($place = new LoadConst($constantSymbol.info));
}
;
arrayIdx
returns [Instruction place, BasicBlock code]
: constantSymbol
{
$code = new BasicBlock();
$code.add($place = new LoadConst($constantSymbol.info));
}
| variableSymbol
{
$code = new BasicBlock();
$code.add($place = new LoadVariable($variableSymbol.info));
}
;
decl
: arrayDecl
| variableDecl[false]
;
variableDecl[boolean immutable]
returns [VariableSymbolInfo info]
: symbol
{
$info = new VariableSymbolInfo(Location.fromContext($ctx), $immutable);
if (table.lookup($symbol.symb) != null) {
log.error(Location.fromContext($ctx), "redefinition of symbol {0}",
$symbol.symb.getUniqueName());
return;
}
table.insert($symbol.symb, $info);
}
;
arrayDecl
locals [ArraySymbolInfo info]
: symbol '(' low=rawNumber ':' high=rawNumber ')'
{
if ($low.val > $high.val) {
log.error(Location.fromContext($ctx), "declaring array {0} with invalid bounds",
$symbol.symb.getUniqueName());
return;
}
$info = new ArraySymbolInfo(Location.fromContext($ctx), $low.val, $high.val);
if (table.lookup($symbol.symb) != null) {
log.error(Location.fromContext($ctx), "redefinition of symbol {0}",
$symbol.symb.getUniqueName());
return;
}
table.insert($symbol.symb, $info);
}
;
arraySymbol
returns [ArraySymbolInfo info]
locals [SymbolInfo rawInfo]
: symbol
{
$rawInfo = table.lookup($symbol.symb);
if ($rawInfo == null) {
log.error(Location.fromContext($ctx), "{0} is not defined", $symbol.symb.getUniqueName());
return;
} else if (!$rawInfo.isArray()) {
log.error(Location.fromContext($ctx), "{0} is not an array", $symbol.symb.getUniqueName());
return;
}
$info = $rawInfo.asArray();
}
;
variableSymbol
returns [VariableSymbolInfo info]
locals [SymbolInfo rawInfo]
: symbol
{
$rawInfo = table.lookup($symbol.symb);
if ($rawInfo == null) {
log.error(Location.fromContext($ctx), "{0} is not defined", $symbol.symb.getUniqueName());
return;
} else if (!$rawInfo.isVariable()) {
log.error(Location.fromContext($ctx), "{0} is not a variable", $symbol.symb.getUniqueName());
return;
}
$info = $rawInfo.asVariable();
}
;
constantSymbol
returns [ConstantSymbolInfo info]
: rawNumber
{
$info = table.lookup(Long.toString($rawNumber.val));
if ($info == null) table.insert(Long.toString($rawNumber.val), new ConstantSymbolInfo($rawNumber.val));
}
;
symbol
returns [Symbol symb]
: Identifier
{
$symb = new Symbol(null, $Identifier.text);
}
;
rawNumber
returns [long val]
: Number
{
try {
$val = Long.parseLong($Number.text);
} catch (NumberFormatException e) {
log.error(Location.fromContext($ctx), "{0} is not valid 64-bit integer", $Number.text);
}
}
;
Identifier
: ('a' .. 'z' | '_')+
;
Number
: '0' | [1-9][0-9]*
;
Ws
: (' ' | '\n' | '\r' | '\t')+
;
Comment
: '[' .*? ']'
;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment