/**
*
* MackASM grammar defintion
for use with JavaCC
*
**/
options { JDK_VERSION = "1.5"; }
PARSER_BEGIN( MackASM )
package parser;
import java.util.*;
import editor.Mack;
public class MackASM
{
public static Mack mack = null;
}
PARSER_END( MackASM )
SKIP : {
" "
| "\t"
| "\n"
| "\r"
| <"//" (~["\n","\r"])* ("\n" | "\r" | "\r\n")>
| <"/*" (~["*"])* "*" ("*" | ~["*","/"] (~["*"])* "*")* "/">
}
TOKEN : {
<INTEGER_LITERAL: <DECIMAL_LITERAL> | <HEX_LITERAL> >
| <#DECIMAL_LITERAL: ["0"-"9"] (["0"-"9"])*>
| <#HEX_LITERAL: "0" ["x","X"] (["0"-"9","a"-"f","A"-"F"])+>
| <CHARACTER_LITERAL: "\'" (~["\'","\\","\n","\r"] | "\\" (["n","t","b","r","f","\\","\'","\""] | ["0"-"9"] (["0"-"9"])? | ["0"-"2"] ["0"-"9"] ["0"-"9"])) "\'">
| <STRING_LITERAL: "\"" ( ~["\"","\\","\n","\r"] | "\\" ( ["n","t","b","r","f","\\","\'","\""] | ["0"-"9"] (["0"-"9"])? | ["0"-"2"] ["0"-"9"] ["0"-"9"] | ( ["\n","\r"] | "\r\n")))* "\"">
}
TOKEN : {
<SYSCALL: "syscall">
|
<SECTION: "SECTION">
|
<ARSHIFT: "arshift">
|
<RETURN:
"return"> |
<RSHIFT:
"rshift"> |
<STRING:
"string"> |
<LSHIFT:
"lshift"> |
<CONST: "const"> |
<CLEAR: "clear"> |
<START: "START"> |
<ARRAY: "array"> |
<STORE: "store"> |
<DOT_FAR: ".far"> |
<DATA_SEC:"DATA"> |
<DATA: "data"> |
<CODE_SEC:"CODE"> |
<PUSH: "push"> |
<CALL: "call"> |
<LOAD: "load"> |
<BSS_SEC: "BSS"> |
<DOT_DNZ: ".dnz"> |
<POP: "pop"> |
<DUP: "dup"> |
<ADD: "add"> |
<SUB: "sub"> |
<MUL: "mul"> |
<DIV: "div"> |
<AND: "and"> |
<XOR: "xor"> |
<NOT: "not"> |
<NEG: "neg"> |
<DOT_NEG1:".-1"> |
<DOT_LT:
".<"> |
<DOT_LE:
".<="> |
<DOT_EQ:
".="> |
<DOT_NE:
".<>"> |
<DOT_GE:
".>="> |
<DOT_GT:
".>"> |
<ARROW: "->"> |
<DOT_P: ".p"> |
<DOT_B: ".b"> |
<DOT_L: ".l"> |
<OR: "or"> |
<B: "b"> |
<COLON: ":">
}
TOKEN : {
<IDENTIFIER: <LETTER> (<LETTER> | <DIGIT>)*>
| <#LETTER: ["$","A"-"Z","_","a"-"z"]>
| <#DIGIT: ["0"-"9"]>
}
void MackASMdoc( Mack mackFile ) : {mack = mackFile;}
{
( ConstDef() )*
[ LOOKAHEAD(2) BssSectionDef() ]
[ LOOKAHEAD(2) DataSectionDef() ]
CodeSectionDef()
< EOF >
}
void ConstDef() : {Token name; int
value;}
{
name= <IDENTIFIER>
<CONST>
value= Expr() {
mack.defConst(name, value); }
}
int Expr(): { int a; int
b; }
{
a= term()
(
"+" b= Expr() { a += b; }
|
"-" b= Expr() { a -= b; }
)* { return a; }
}
int term(): { int a; int
b; }
{
a= unary()
(
"*" b= term() { a *= b; }
|
"/" b= term() { a /= b; }
)* { return a; }
}
int unary(): { int
a; }
{
"-" a= element() { return -a; }
|
a= element() { return a; }
}
int element(): { Token tok; int a; }
{
tok= <INTEGER_LITERAL> { return mack.parseInt(tok); }
|
LOOKAHEAD(
{getToken(1).kind==IDENTIFIER
&&
getToken(2).kind!=COLON} )
tok= <IDENTIFIER> { return mack.ref(tok); }
|
"(" a=Expr() ")" { return a; }
}
void BssSectionDef() : {}
{
<START> <BSS_SEC> [ <SECTION> ]
( LOOKAHEAD(2) BssDef() | ConstDef() )*
}
void BssDef() : { Token name=null; int size=2; int initValue; int
repeat=1; }
{
[ name= <IDENTIFIER> ]
(
<DATA>
[ <DOT_B> {size=1;} | <DOT_L> {size=4;} ]
|
<ARRAY> [ <DOT_B> {size=1;} | <DOT_L> {size=4;} ] "[" repeat= Expr() "]"
)
{ mack.defBss(name,
size, repeat); }
}
void DataSectionDef() : {}
{
<START> <DATA_SEC> [ <SECTION> ]
( LOOKAHEAD(2) DataDef() | ConstDef() )*
}
void DataDef() : { Token name=null; int size=2; int initValue; int
repeat=1; Token str; }
{
[ name= <IDENTIFIER> ]
(
<DATA>
[ <DOT_B> {size=1;} | <DOT_L> {size=4;} ] initValue=
Expr() {
mack.defData(name, size, initValue, 1); }
|
<ARRAY> [ <DOT_B> {size=1;} | <DOT_L> {size=4;} ] initValue= Expr() "[" repeat= Expr() "]"{ mack.defData(name, size,
initValue, repeat); }
|
<STRING> str=<STRING_LITERAL> {
mack.defString(name, str); }
)
}
void CodeSectionDef() : {}
{
<START> <CODE_SEC> [ <SECTION> ]
( LOOKAHEAD(2) CodeDef() | ConstDef() )*
}
void CodeDef() : { Token tok; int value; int
sizeMask; mack.resetLoadSize(); }
{
[ tok= <IDENTIFIER> <COLON> { mack.defLabel(tok); } ]
( LOOKAHEAD(2)
<PUSH>
<ARROW> tok= <IDENTIFIER> value= LabelDistance() {
mack.genPushLabel(tok,value); }
|
tok= <PUSH> value= Expr()
{ mack.genPush(value); }
|
tok= <POP> { mack.genOp(0xC0, tok, -1);
}
|
tok= <CLEAR> { mack.genOp(0xC1, tok, -999);
}
|
tok= <DUP> ( <DOT_NEG1> {mack.genOp(0xC3, tok, +1);} | Operands1() {mack.genOp(0xC2, tok,
+1);} )
|
tok= <ADD> Operands2() { mack.genOp(0xC4, tok,
-1); }
|
tok= <SUB> Operands2() { mack.genOp(0xC5, tok,
-1); }
|
tok= <MUL> Operands2() { mack.genOp(0xC6, tok,
-1); }
|
tok= <DIV> Operands2() { mack.genOp(0xC7, tok,
-1); }
|
tok= <AND> Operands2() { mack.genOp(0xC8, tok,
-1); }
|
tok= <OR> Operands2() { mack.genOp(0xC9,
tok, -1); }
|
tok= <XOR> Operands2() { mack.genOp(0xCA, tok,
-1); }
|
tok= <ARSHIFT> Operands2() { mack.genOp(0xCB, tok,
-1); }
|
tok= <RSHIFT> Operands2() { mack.genOp(0xCC, tok,
-1); }
|
tok= <LSHIFT> Operands2() { mack.genOp(0xCD, tok,
-1); }
|
tok= <NOT> Operands1() { mack.genOp(0xCE, tok,
0); }
|
tok= <NEG> Operands1() { mack.genOp(0xCF, tok,
0); }
|
tok= <B> CondBranch(0xD0, tok)
|
tok= <RETURN> { mack.genOp(0xD7, tok, -1); }
|
tok= <SYSCALL> Operands() { mack.genOp(0xD8, tok,
-999); }
|
tok= <CALL> CondBranch(0xD8, tok)
|
tok= <LOAD> sizeMask= MemCompleters() { mack.genOp(0xE0 | sizeMask, tok, 0);
}
|
tok= <STORE> sizeMask= MemCompleters() ["," value= Expr()
{mack.genPush(value);} ]
{mack.genOp(0xF0 |
sizeMask, tok, -2); }
)
}
void CondBranch( int
opCode, Token tok ) : { int value; int
condCode=7; Token labTok=null; int
howFar=0; }
{
[
LOOKAHEAD( {getToken(1).kind==DOT_DNZ &&
token.kind==B} )
<DOT_DNZ> value=
Expr() { mack.genPush(value); condCode=0; }
|
<DOT_GT>
Operands2()
{ condCode=1; }
|
<DOT_EQ> Operands2() { condCode=2; }
|
<DOT_GE> Operands2() { condCode=3; }
|
<DOT_LT> Operands2() { condCode=4; }
|
<DOT_NE> Operands2() { condCode=5; }
|
<DOT_LE> Operands2() { condCode=6; }
]
[
<ARROW> labTok= <IDENTIFIER> howFar= LabelDistance()
]
{
mack.genBranch(opCode | condCode, tok, labTok, howFar); }
}
// Each ".far" after the label means another byte is
needed to push the label.
int LabelDistance() : { int howFar=0; }
{
(
<DOT_FAR> { howFar++; }
)* { return howFar; }
}
// MemCompleters() is used to LOAD and STORE stuff. These instructions do not use Operands()
// because we do not want the variables to auto load. We just want
their address pushed.
int MemCompleters() : { int
value; int mem=0; int size=2; }
{
[<DOT_P> {mem=0x04;}]
[<DOT_B> {size=0x01;} | <DOT_L> {size=0x03;}]
[LOOKAHEAD(Expr())
value= Expr() {
mack.genPush(value); }
]
{ return mem | size; }
}
// Any number of operands.
void Operands() : {}
{
[ LOOKAHEAD(1)
Operand() ( LOOKAHEAD(1) "," Operand() )*
]
}
// 0, 1, 2 or 3 operands.
void Operands3() : {}
{
[ Operand() [ "," Operand() [ "," Operand() ] ] ]
}
// 0, 1 or 2 operands.
void Operands2() : {}
{
[ LOOKAHEAD(1)
Operand() [ "," Operand() ]
]
}
// 0 or 1 operand.
void Operands1() : {}
{
[ LOOKAHEAD(1)
Operand()
]
}
// When an Expression sees a variable, it sets a global called
"loadSize".
// If loadSize is set, this assumes you want to do a load, else it
just pushes the value.
void Operand() : { int value; mack.resetLoadSize(); }
{
value= Expr() {
mack.genPushOrLoad(value); }
}