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 }