1 using AssemblyTokens;
2
3 parser AssemblyParser
4 {
5 uselexer AssemblyLexer;
6 main;
7
8 AssemblyFile(List<UniquePtr<cmsx.assembly.Instruction>>* instructionList)
9 ::= AssemblyLine(instructionList):assemblyLine*
10 ;
11
12 AssemblyLine(List<UniquePtr<cmsx.assembly.Instruction>>* instructionList)
13 ::= CommentLine:commentLine
14 | EmptyLine:emptyLine
15 | ModeLine(instructionList):modeLine
16 | InstructionLine(instructionList):instructionLine
17 ;
18
19 CommentLine
20 ::= Comment:cmt NEWLINE
21 ;
22
23 Comment
24 ::= SPACE? (any - (NEWLINE | SYMBOL | LOCAL_SYMBOL | DOT | SEMICOLON | AT)) (any - NEWLINE)*
25 ;
26
27 EmptyLine
28 ::= SPACE? NEWLINE
29 ;
30
31 ModeLine(List<UniquePtr<cmsx.assembly.Instruction>>* instructionList)
32 ::= SPACE?
33 DOT
34 SYMBOL
35 {
36 cmsx.assembly.Instruction* modeInst = cmsx.assembly.MakeModeInst(span, lexer.GetToken(pos));
37 pass = modeInst != null;
38 if (pass)
39 {
40 instructionList->Add(UniquePtr<cmsx.assembly.Instruction>(modeInst));
41 }
42 }
43 SPACE?
44 NEWLINE
45 ;
46
47 InstructionLine(List<UniquePtr<cmsx.assembly.Instruction>>* instructionList)
48 ::= Instruction:left{ instructionList->Add(UniquePtr<cmsx.assembly.Instruction>(left)); }
49 (SPACE? SEMICOLON Instruction:right{ instructionList->Add(UniquePtr<cmsx.assembly.Instruction>(right)); })* Comment:cmt? NEWLINE
50 ;
51
52 Instruction(var Span s, var UniquePtr<cmsx.assembly.Node> label) : cmsx.assembly.Instruction*
53 ::=
54 (
55 empty{ lexer.PushSpan(); }
56 Label:lbl{ lexer.SetSpan(pos); label.Reset(lbl); }
57 SplitLine(!label.IsNull()):splitLine{ lexer.SetSpan(pos); }
58 OpCode:opcode{ lexer.SetSpan(pos); }
59 Operands:operands{ lexer.SetSpan(pos); }
60 )
61 {
62 return new cmsx.assembly.Instruction(lexer.PopSpan(), label.Release(), opcode, operands);
63 }
64 ;
65
66 Label : cmsx.assembly.Node*
67 ::= LOCAL_SYMBOL{ return cmsx.assembly.MakeLocalSymbolNode(span, lexer.GetToken(pos)); }
68 | SYMBOL{ return cmsx.assembly.MakeSymbolNode(span, lexer.GetToken(pos)); }
69 | empty{ return null; }
70 ;
71
72 SplitLine(bool hasLabel)
73 ::= SPACE (NEWLINE SPACE)?
74 | empty{ pass = hasLabel; } NEWLINE SPACE
75 ;
76
77 OpCode : cmsx.assembly.OpCode*
78 ::= empty{ lexer.PushSpan(); } (DECIMAL_CONSTANT{ lexer.SetSpan(pos); })? SYMBOL{ lexer.SetSpan(pos); Span s = lexer.PopSpan(); return cmsx.assembly.MakeOpCode(s, lexer.GetMatch(s)); }
79 ;
80
81 Operands(var UniquePtr<cmsx.assembly.OperandList> operandList) : cmsx.assembly.OperandList*
82 ::=
83 ( SPACE? Expression:left{ operandList.Reset(new cmsx.assembly.OperandList(span, left)); } (COMMA Expression:right{ operandList->AddOperand(right); })*
84 | SPACE? empty{ operandList.Reset(new cmsx.assembly.OperandList(span, new cmsx.assembly.DecimalConstant(span, 0u))); }
85 )
86 {
87 return operandList.Release();
88 }
89 ;
90
91 Expression(var UniquePtr<cmsx.assembly.Node> expr) : cmsx.assembly.Node*
92 ::=
93 (
94 Term:left{ expr.Reset(left); } (WeakOperator:op Term:right{ expr.Reset(new cmsx.assembly.BinaryExpression(span, expr.Release(), op, right)); })*
95 )
96 {
97 return expr.Release();
98 }
99 ;
100
101 WeakOperator : cmsx.assembly.Operator
102 ::= PLUS{ return cmsx.assembly.Operator.add; }
103 | MINUS{ return cmsx.assembly.Operator.subtract; }
104 | BAR{ return cmsx.assembly.Operator.bitwiseOr; }
105 | CARET{ return cmsx.assembly.Operator.bitwiseXor; }
106 ;
107
108 Term(var UniquePtr<cmsx.assembly.Node> expr) : cmsx.assembly.Node*
109 ::=
110 (
111 PrimaryExpression:left{ expr.Reset(left); } (StrongOperator:op PrimaryExpression:right{ expr.Reset(new cmsx.assembly.BinaryExpression(span, expr.Release(), op, right)); })*
112 )
113 {
114 return expr.Release();
115 }
116 ;
117
118 StrongOperator : cmsx.assembly.Operator
119 ::= AST{ return cmsx.assembly.Operator.multiply; }
120 | SLASH{ return cmsx.assembly.Operator.divide; }
121 | SLASHSLASH{ return cmsx.assembly.Operator.fractionalDivide; }
122 | PERCENT{ return cmsx.assembly.Operator.modulus; }
123 | SHIFT_LEFT{ return cmsx.assembly.Operator.shiftLeft; }
124 | SHIFT_RIGHT{ return cmsx.assembly.Operator.shiftRight; }
125 | AMP{ return cmsx.assembly.Operator.bitwiseAnd; }
126 ;
127
128 PrimaryExpression(var Span s) : cmsx.assembly.Node*
129 ::= LocalSymbol:localSymbol{ return localSymbol; }
130 | Constant:constant{ return constant; }
131 | Symbol:symbol{ return symbol; }
132 | At:at{ return at; }
133 | LPAREN{ s = span; } Expression:expr RPAREN{ s.end = span.end; return new cmsx.assembly.ParenthesizedExpression(s, expr); }
134 | UnaryOperator:op{ s = span; } PrimaryExpression:primaryExpr{ s.end = span.end; return new cmsx.assembly.UnaryExpression(s, op, primaryExpr); }
135 ;
136
137 UnaryOperator : cmsx.assembly.Operator
138 ::= PLUS{ return cmsx.assembly.Operator.unaryPlus; }
139 | MINUS{ return cmsx.assembly.Operator.unaryMinus; }
140 | TILDE{ return cmsx.assembly.Operator.complement; }
141 | DOLLAR{ return cmsx.assembly.Operator.register; }
142 | AMP{ return cmsx.assembly.Operator.serial; }
143 ;
144
145 LocalSymbol : cmsx.assembly.Node*
146 ::= LOCAL_SYMBOL{ return cmsx.assembly.MakeLocalSymbolNode(span, lexer.GetToken(pos)); }
147 ;
148
149 Constant : cmsx.assembly.Node*
150 ::= DECIMAL_CONSTANT{ return new cmsx.assembly.DecimalConstant(span, ParseULong(ToUtf8(lexer.GetMatch(span)))); }
151 | HEX_CONSTANT{ return cmsx.assembly.MakeHexConstant(span, lexer.GetToken(pos)); }
152 | CHAR_CONSTANT{ return cmsx.assembly.MakeCharConstant(span, lexer.GetToken(pos)); }
153 | STRING_CONSTANT{ return cmsx.assembly.MakeStringConstant(span, lexer.GetToken(pos)); }
154 | CLSID_CONSTANT{ return cmsx.assembly.MakeClsIdConstant(span, lexer.GetToken(pos)); }
155 ;
156
157 Symbol : cmsx.assembly.Node*
158 ::= SYMBOL{ return cmsx.assembly.MakeSymbolNode(span, lexer.GetToken(pos)); }
159 ;
160
161 At : cmsx.assembly.Node*
162 ::= AT{ return new cmsx.assembly.At(span); }
163 ;
164 }