1 // =================================
  2 // Copyright (c) 2021 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 using IntermediateCodeTokens;
  7 
  8 parser IntermediateCodeFileParser
  9 {
 10     uselexer IntermediateCodeLexer;
 11     main;
 12 
 13     IntermediateCodeFile(cmsx.intermediate.Context* context)
 14         ::= empty{ context->SetFileName(lexer.FileName()); }
 15             CompileUnitHeader(context):header
 16             TypeDeclarations(context):typeDeclarations?
 17             DataDefinitions(context):dataDefinitions?
 18             Functions(context):functions?
 19             Metadata(context):metadata?
 20         ;
 21 
 22     CompileUnitHeader(cmsx.intermediate.Context* context)
 23         ::= CU LPAREN! CompileUnitId:cuid! COMMA! MDStructRef(context):mdRef! RPAREN!
 24         {
 25             context->SetCompileUnitInfo(cuid, mdRef);
 26         }
 27         ;
 28 
 29     CompileUnitId : string
 30         ::= HEXNUM{ return ToUtf8(lexer.GetToken(pos).match.ToString()); }
 31         |   NUMBER{ return ToUtf8(lexer.GetToken(pos).match.ToString()); }
 32         |   ID{ return ToUtf8(lexer.GetToken(pos).match.ToString()); }
 33         ;
 34 
 35     TypeDeclarations(cmsx.intermediate.Context* context)
 36         ::= TYPES LBRACE! TypeDeclaration(context):typeDeclaration* RBRACE!{ context->ResolveTypes(); }
 37         ;
 38 
 39     TypeDeclaration(cmsx.intermediate.Context* context, var string typeId)
 40         ::= StrTypeId(context):tid{ typeId = tid; } ASSIGN! TYPE!
 41         (   StructureType(typeId, context):structureType
 42         |   ArrayType(typeId, context):arrayType
 43         |   FunctionType(typeId, context):functionType
 44         )
 45         ;
 46 
 47     StrTypeId(cmsx.intermediate.Context* context, var string str) : string
 48         ::=
 49         (
 50             (   TYPEID{ str = ToUtf8(lexer.GetToken(pos).match.ToString()); }
 51             |   PrimitiveTypeName:primitiveTypeName{ str = primitiveTypeName; }
 52             )
 53             (AST{ str.Append('*'); context->AddPtrType(str, span.line); })*
 54         )
 55         {
 56             return str;
 57         }
 58         ;
 59 
 60     StructureType(string typeId, cmsx.intermediate.Context* context, var List<string> memberTypeIds)
 61         ::= (LBRACE ((StrTypeId(context):tid!{ memberTypeIds.Add(tid); } (COLON OFFSET ASSIGN NUMBER)?) % COMMA) RBRACE!){ context->AddStructureType(typeId, memberTypeIds); }
 62             (SIZE ASSIGN NUMBER COMMA ALIGNMENT ASSIGN NUMBER)?
 63         ;
 64 
 65     ArrayType(string typeId, cmsx.intermediate.Context* context, var long size)
 66         ::=
 67         (   LBRACKET
 68             NUMBER!{ size = ParseLong(ToUtf8(lexer.GetToken(pos).match.ToString())); }
 69             ID{ pass = lexer.GetToken(pos).match.ToString() == u"x"; }
 70             StrTypeId(context):elementTypeId!
 71             RBRACKET!
 72         )
 73         {
 74             context->AddArrayType(typeId, elementTypeId, size);
 75         }
 76         (SIZE ASSIGN NUMBER COMMA ALIGNMENT ASSIGN NUMBER)?
 77         ;
 78 
 79     FunctionType(string typeId, cmsx.intermediate.Context* context, var List<string> paramTypeIds)
 80         ::=
 81         (
 82             FUNCTION StrTypeId(context):returnTypeId! LPAREN! (StrTypeId(context):paramType{ paramTypeIds.Add(paramType); } % COMMA)? RPAREN!
 83         )
 84         {
 85             context->AddFunctionType(typeId, returnTypeId, paramTypeIds);
 86         }
 87         ;
 88 
 89     DataDefinitions(cmsx.intermediate.Context* context)
 90         ::= (DATA LBRACE! DataDefinition(context):dataDefinition* RBRACE!){ context->ValidateGlobalVariables(); }
 91         ;
 92 
 93     DataDefinition(cmsx.intermediate.Context* context, var bool once, var string variableName, var cmsx.intermediate.Type* type)
 94         ::= TypeExpr(context):t{ type = t; } (ONCE{ once = true; })? ID!{ variableName = ToUtf8(lexer.GetToken(pos).match.ToString()); }
 95             (   SEMICOLON{ context->AddGlobalVariable(type, variableName, cast<cmsx.intermediate.ConstantValue*>(null), span.line, once); }
 96             |   ASSIGN! Constant(context):constant{ context->AddGlobalVariable(type, variableName, constant, span.line, once); }
 97             )
 98         ;
 99 
100     Functions(cmsx.intermediate.Context* context)
101         ::= Function(context):function*
102         ;
103 
104     Function(cmsx.intermediate.Context* context, var cmsx.intermediate.Function* function)
105         ::= FunctionHeader(context):fun{ function = fun; context->SetCurrentFunction(function); } LBRACE! BasicBlock(context, function):bb* RBRACE!
106         ;
107 
108     FunctionHeader(cmsx.intermediate.Context* context, var bool once, var string functionId,  var cmsx.intermediate.Type* functionType) : cmsx.intermediate.Function*
109         ::= FUNCTION TypeExpr(context):t!{ functionType = t; } (ONCE{ once = true; })? ID!{ functionId = ToUtf8(lexer.GetToken(pos).match.ToString()); } (MDStructRef(context):md?)
110         {
111             return context->AddFunction(span.line, functionType, functionId, once, md);
112         }
113         ;
114 
115     BasicBlock(cmsx.intermediate.Context* context, cmsx.intermediate.Function* function, var cmsx.intermediate.BasicBlock* bb)
116         ::= Label:id{ bb = function->AddBasicBlock(id); } Instructions(context, bb):instructions
117         ;
118 
119     Label : uint
120         ::= AT NUMBER{ return ParseUInt(ToUtf8(lexer.GetToken(pos).match.ToString())); }
121         ;
122 
123     Instructions(cmsx.intermediate.Context* context, cmsx.intermediate.BasicBlock* bb)
124         ::=
125         (
126             (Instruction(context):instruction (MDStructRef(context):lineInfo)?){ bb->AddInstruction(instruction, lineInfo); }
127         )+
128         ;
129 
130     Instruction(cmsx.intermediate.Context* context) : cmsx.intermediate.Instruction*
131         ::= StoreInstruction(context):store{ return store; }
132         |   ArgInstruction(context):arg{ return arg; }
133         |   JumpInstruction(context):jmp{ return jmp; }
134         |   BranchInstruction(context):branch{ return branch; }
135         |   ProcedureCallInstruction(context):call{ return call; }
136         |   RetInstruction(context):ret{ return ret; }
137         |   SwitchInstruction(context):swtch{ return swtch; }
138         |   ValueInstruction(context):valueInst{ return valueInst; }
139         |   NoOperationInstruction(context):nopInst{ return nopInst; }
140         |   SaveInstruction(context):saveInst{ return saveInst; }
141         ;
142 
143     StoreInstruction(cmsx.intermediate.Context* context, var cmsx.intermediate.Type* type, var cmsx.intermediate.Type* ptrType) : cmsx.intermediate.Instruction*
144         ::= STORE TypeExpr(context):t!{ type = t; } TypedValue(context, type):val! COMMA! TypeExpr(context):pt!{ ptrType = pt; } TypedValue(context, ptrType):ptr!
145         {
146             return new cmsx.intermediate.StoreInstruction(val, ptr, span.line);
147         }
148         ;
149 
150     ArgInstruction(cmsx.intermediate.Context* context, var cmsx.intermediate.Type* type) : cmsx.intermediate.Instruction*
151         ::= ARG TypeExpr(context):t!{ type = t; } TypedValue(context, type):arg!
152         {
153             return new cmsx.intermediate.ArgInstruction(arg, span.line);
154         }
155         ;
156 
157     JumpInstruction(cmsx.intermediate.Context* context) : cmsx.intermediate.Instruction*
158         ::= JMP Label:target!
159         {
160             return new cmsx.intermediate.JumpInstruction(target, span.line);
161         }
162         ;
163 
164     BranchInstruction(cmsx.intermediate.Context* context, var cmsx.intermediate.Type* type) : cmsx.intermediate.Instruction*
165         ::= BRANCH TypeExpr(context):t!{ type = t; } TypedValue(context, type):cond! COMMA! Label:trueTarget! COMMA! Label:falseTarget!
166         {
167             return new cmsx.intermediate.BranchInstruction(cond, trueTarget, falseTarget, span.line);
168         }
169         ;
170 
171     ProcedureCallInstruction(cmsx.intermediate.Context* context, var cmsx.intermediate.Type* functionType) : cmsx.intermediate.Instruction*
172         ::= CALL TypeExpr(context):ft!{ functionType = ft; } TypedValue(context, functionType):callee!
173         {
174             return new cmsx.intermediate.ProcedureCallInstruction(callee, span.line);
175         }
176         ;
177 
178     RetInstruction(cmsx.intermediate.Context* context, var cmsx.intermediate.Type* type) : cmsx.intermediate.Instruction*
179         ::= RET
180         (   (VOID - (VOID AST)){ return new cmsx.intermediate.RetInstruction(null, span.line); }
181         |   TypeExpr(context):t{ type = t; } TypedValue(context, type):val{ return new cmsx.intermediate.RetInstruction(val, span.line); }
182         )
183         ;
184 
185     SwitchInstruction(cmsx.intermediate.Context* context, var cmsx.intermediate.SwitchInstruction* inst, var cmsx.intermediate.Type* type, var cmsx.intermediate.Type* caseType) :
186             cmsx.intermediate.SwitchInstruction*
187         ::=
188         (
189             SWITCH TypeExpr(context):t!{ type = t; } TypedValue(context, type):cond! Label:defaultTarget!{ inst = new cmsx.intermediate.SwitchInstruction(cond, defaultTarget, span.line); }
190             COMMA!
191             LBRACKET! ((TypeExpr(context):ct{ caseType = ct; } TypedValue(context, caseType):caseValue COMMA Label:caseTarget){ inst->AddCase(caseValue, caseTarget); } % COLON) RBRACKET!
192         )
193         {
194             return inst;
195         }
196         ;
197 
198     ValueInstruction(cmsx.intermediate.Context* context, var cmsx.intermediate.Type* type, var cmsx.intermediate.Value* result) : cmsx.intermediate.Instruction*
199         ::= TypeExpr(context):t{ type = t; } TypedValue(context, type):r!{ result = r; } ASSIGN Operation(context, result):op!
200         {
201             return op;
202         }
203         ;
204 
205     Operation(cmsx.intermediate.Context* context, cmsx.intermediate.Value* result) : cmsx.intermediate.Instruction*
206         ::= UnaryInstruction(context, result):unaryInst{ return unaryInst; }
207         |   BinaryInstruction(context, result):binaryInst{ return binaryInst; }
208         |   ParamInstruction(context, result):paramInst{ return paramInst; }
209         |   LocalInstruction(context, result):localInst{ return localInst; }
210         |   LoadInstruction(context, result):loadInst{ return loadInst; }
211         |   ElemAddrInstruction(context, result):elemAddrInst{ return elemAddrInst; }
212         |   PtrOffsetInstruction(context, result):ptrOffsetInst{ return ptrOffsetInst; }
213         |   PtrDiffInstruction(context, result):ptrDiffInst{ return ptrDiffInst; }
214         |   FunctionCallInstruction(context, result):functionCallInst{ return functionCallInst; }
215         |   TrapInstruction(context, result):trapInst{ return trapInst; }
216         ;
217 
218     UnaryInstruction(cmsx.intermediate.Context* context, cmsx.intermediate.Value* result, var cmsx.intermediate.UnaryInstruction* inst) : cmsx.intermediate.Instruction*
219         ::= UnaryInst:unaryInst{ inst = unaryInst; } Operand(context):arg!{ inst->SetOperand(arg); inst->SetResult(result); return inst; }
220         ;
221 
222     UnaryInst : cmsx.intermediate.UnaryInstruction* 
223         ::= NOT{ return new cmsx.intermediate.NotInstruction(span.line); }
224         |   NEG{ return new cmsx.intermediate.NegInstruction(span.line); }
225         |   SIGNEXTEND{ return new cmsx.intermediate.SignExtendInstruction(span.line); }
226         |   ZEROEXTEND{ return new cmsx.intermediate.ZeroExtendInstruction(span.line); }
227         |   TRUNCATE{ return new cmsx.intermediate.TruncateInstruction(span.line); }
228         |   BITCAST{ return new cmsx.intermediate.BitCastInstruction(span.line); }
229         |   INTTOFLOAT{ return new cmsx.intermediate.IntToFloatInstruction(span.line); }
230         |   FLOATTOINT{ return new cmsx.intermediate.FloatToIntInstruction(span.line); }
231         |   INTTOPTR{ return new cmsx.intermediate.IntToPtrInstruction(span.line); }
232         |   PTRTOINT{ return new cmsx.intermediate.PtrToIntInstruction(span.line); }
233         ;
234 
235     BinaryInstruction(cmsx.intermediate.Context* context, cmsx.intermediate.Value* result, var cmsx.intermediate.BinaryInstruction* inst) : cmsx.intermediate.Instruction*
236         ::= BinaryInst:binaryInst{ inst = binaryInst; } Operand(context):left! COMMA! Operand(context):right!{ inst->SetOperands(left, right); inst->SetResult(result); return inst; }
237         ;
238 
239     BinaryInst : cmsx.intermediate.BinaryInstruction*
240         ::= ADD{ return new cmsx.intermediate.AddInstruction(span.line); }
241         |   SUB{ return new cmsx.intermediate.SubInstruction(span.line); }
242         |   MUL{ return new cmsx.intermediate.MulInstruction(span.line); }
243         |   DIV{ return new cmsx.intermediate.DivInstruction(span.line); }
244         |   MOD{ return new cmsx.intermediate.ModInstruction(span.line); }
245         |   AND{ return new cmsx.intermediate.AndInstruction(span.line); }
246         |   OR{ return new cmsx.intermediate.OrInstruction(span.line); }
247         |   XOR{ return new cmsx.intermediate.XorInstruction(span.line); }
248         |   SHL{ return new cmsx.intermediate.ShlInstruction(span.line); }
249         |   SHR{ return new cmsx.intermediate.ShrInstruction(span.line); }
250         |   EQUAL{ return new cmsx.intermediate.EqualInstruction(span.line); }
251         |   LESS{ return new cmsx.intermediate.LessInstruction(span.line); }
252         ;
253 
254     ParamInstruction(cmsx.intermediate.Context* context, cmsx.intermediate.Value* result) : cmsx.intermediate.Instruction*
255         ::= PARAM{ return new cmsx.intermediate.ParamInstruction(result, span.line); }
256         ;
257 
258     LocalInstruction(cmsx.intermediate.Context* context, cmsx.intermediate.Value* result, var cmsx.intermediate.Type* localType) : cmsx.intermediate.Instruction*
259         ::= (LOCAL TypeExpr(context):t!{ localType = t; }){ return new cmsx.intermediate.LocalInstruction(result, localType, span.line); }
260         ;
261 
262     LoadInstruction(cmsx.intermediate.Context* context, cmsx.intermediate.Value* result) : cmsx.intermediate.Instruction*
263         ::= (LOAD Operand(context):ptr!){ return new cmsx.intermediate.LoadInstruction(result, ptr, span.line); }
264         ;
265 
266     ElemAddrInstruction(cmsx.intermediate.Context* context, cmsx.intermediate.Value* result) : cmsx.intermediate.Instruction*
267         ::= (ELEMADDR Operand(context):ptr! COMMA! Operand(context):index!){ return new cmsx.intermediate.ElemAddrInstruction(result, ptr, index, span.line); }
268         ;
269 
270     PtrOffsetInstruction(cmsx.intermediate.Context* context, cmsx.intermediate.Value* result) : cmsx.intermediate.Instruction*
271         ::= (PTROFFSET Operand(context):ptr! COMMA! Operand(context):offset!){ return new cmsx.intermediate.PtrOffsetInstruction(result, ptr, offset, span.line); }
272         ;
273 
274     PtrDiffInstruction(cmsx.intermediate.Context* context, cmsx.intermediate.Value* result) : cmsx.intermediate.Instruction*
275         ::= (PTRDIFF Operand(context):leftPtr! COMMA! Operand(context):rightPtr!){ return new cmsx.intermediate.PtrDiffInstruction(result, leftPtr, rightPtr, span.line); }
276         ;
277 
278     FunctionCallInstruction(cmsx.intermediate.Context* context, cmsx.intermediate.Value* result, var cmsx.intermediate.Type* functionType) : cmsx.intermediate.Instruction*
279         ::= (CALL TypeExpr(context):ft!{ functionType = ft; } TypedValue(context, functionType):callee!){ return new cmsx.intermediate.FunctionCallInstruction(result, callee, span.line); }
280         ;
281 
282     TrapInstruction(cmsx.intermediate.Context* context, cmsx.intermediate.Value* result, var cmsx.intermediate.Type* type1, var cmsx.intermediate.Type* type2, var cmsx.intermediate.Type* type3) :
283         cmsx.intermediate.Instruction*
284         ::=
285         (   TRAP
286             TypeExpr(context):t1!{ type1 = t1; } TypedValue(context, type1):val1! COMMA!
287             TypeExpr(context):t2!{ type2 = t2; } TypedValue(context, type2):val2! COMMA!
288             TypeExpr(context):t3!{ type3 = t3; } TypedValue(context, type3):val3!
289         )
290         {
291             return new cmsx.intermediate.TrapInstruction(result, val1, val2, val3, span.line);
292         }
293         ;
294 
295     NoOperationInstruction(cmsx.intermediate.Context* context) : cmsx.intermediate.Instruction*
296         ::= NOP{ return new cmsx.intermediate.NoOperationInstruction(span.line); }
297         ;
298 
299     SaveInstruction(cmsx.intermediate.Context* context) : cmsx.intermediate.Instruction*
300         ::= SAVE{ return new cmsx.intermediate.SaveInstruction(span.line); }
301         ;
302 
303     Operand(cmsx.intermediate.Context* context, var cmsx.intermediate.Type* type) : cmsx.intermediate.Value*
304         ::= (TypeExpr(context):t{ type = t; } TypedValue(context, type):val!){ return val; }
305         ;
306 
307     TypeExpr(cmsx.intermediate.Context* context) : cmsx.intermediate.Type*
308         ::= PostfixTypeExpr(context):postfix{ return postfix; }
309         ;
310 
311     PostfixTypeExpr(cmsx.intermediate.Context* context, var cmsx.intermediate.Type* type) : cmsx.intermediate.Type*
312         ::= (PrimaryTypeExpr(context):primary{ type = primary; } (AST{ type = context->GetPtrType(type); })*){ return type; }
313         ;
314 
315     PrimaryTypeExpr(cmsx.intermediate.Context* context) : cmsx.intermediate.Type*
316         ::= TypeId(context):typeId{ return typeId; }
317         |   PrimitiveType(context):primitive{ return primitive; }
318         ;
319 
320     TypeId(cmsx.intermediate.Context* context) : cmsx.intermediate.Type*
321         ::= TYPEID{ return context->GetTypeById(span.line, ToUtf8(lexer.GetToken(pos).match.ToString())); }
322         ;
323 
324     PrimitiveType(cmsx.intermediate.Context* context) : cmsx.intermediate.Type*
325         ::= VOID{ return context->GetVoidType(); }
326         |   BOOL{ return context->GetBoolType(); }
327         |   SBYTE{ return context->GetSByteType(); }
328         |   BYTE{ return context->GetByteType(); }
329         |   SHORT{ return context->GetShortType(); }
330         |   USHORT{ return context->GetUShortType(); }
331         |   INT{ return context->GetIntType(); }
332         |   UINT{ return context->GetUIntType(); }
333         |   LONG{ return context->GetLongType(); }
334         |   ULONG{ return context->GetULongType(); }
335         |   FLOAT{ return context->GetFloatType(); }
336         |   DOUBLE{ return context->GetDoubleType(); }
337         ;
338 
339     PrimitiveTypeName : string
340         ::= VOID{ return "void"; }
341         |   BOOL{ return "bool"; }
342         |   SBYTE{ return "sbyte"; }
343         |   BYTE{ return "byte"; }
344         |   SHORT{ return "short"; }
345         |   USHORT{ return "ushort"; }
346         |   INT{ return "int"; }
347         |   UINT{ return "uint"; }
348         |   LONG{ return "long"; }
349         |   ULONG{ return "ulong"; }
350         |   FLOAT{ return "float"; }
351         |   DOUBLE{ return "double"; }
352         ;
353 
354     TypedValue(cmsx.intermediate.Context* context, cmsx.intermediate.Type* type) : cmsx.intermediate.Value*
355         ::= IdValue(context, type):idValue{ return idValue; }
356         |   SymbolValue(context, type):symbolValue{ return symbolValue; }
357         |   LiteralValue(context, type):literalValue{ return literalValue; }
358         ;
359 
360     IdValue(cmsx.intermediate.Context* context, cmsx.intermediate.Type* type) : cmsx.intermediate.Value*
361         ::= DOLLAR NUMBER{ uint x = ParseUInt(ToUtf8(lexer.GetToken(pos).match.ToString())); return context->currentFunction->MakeIdValue(span.line, x, type); }
362         ;
363 
364     SymbolValue(cmsx.intermediate.Context* context, cmsx.intermediate.Type* type) : cmsx.intermediate.ConstantValue*
365         ::= AT ID{ return context->MakeSymbolValue(span.line, ToUtf8(lexer.GetToken(pos).match.ToString()), type); }
366         ;
367 
368     LiteralValue(cmsx.intermediate.Context* context, cmsx.intermediate.Type* type) : cmsx.intermediate.ConstantValue*
369         ::= TRUE{ if (type is cmsx.intermediate.BoolType*) return context->GetBoolType()->MakeBoolValue(true); else context->MakeLiteralValue(span.line, ToUtf8(lexer.GetToken(pos).match.ToString()), type); }
370         |   FALSE{ if (type is cmsx.intermediate.BoolType*) return context->GetBoolType()->MakeBoolValue(false); else context->MakeLiteralValue(span.line, ToUtf8(lexer.GetToken(pos).match.ToString()), type); }
371         |   NULL{ if (type is cmsx.intermediate.PtrType*) return type->DefaultValue(); else context->MakeLiteralValue(span.line, ToUtf8(lexer.GetToken(pos).match.ToString()), type); }
372         |   NUMBER{ return context->MakeLiteralValue(span.line, ToUtf8(lexer.GetToken(pos).match.ToString()), type); }
373         |   ID{ return context->MakeLiteralValue(span.line, ToUtf8(lexer.GetToken(pos).match.ToString()), type); }
374         ;
375 
376     Constant(cmsx.intermediate.Context* context) : cmsx.intermediate.ConstantValue*
377         ::= ConversionConstant(context):conversionConstant{ return conversionConstant; }
378         |   ClsIdConstant(context):clsIdConstant{ return clsIdConstant; }
379         |   PtrConstant(context):ptrConstant{ return ptrConstant; }
380         |   SymbolConstant(context):symbolConstant{ return symbolConstant; }
381         |   BoolConstant(context):boolConstant{ return boolConstant; }
382         |   SByteConstant(context):sbyteConstant{ return sbyteConstant; }
383         |   ByteConstant(context):byteConstant{ return byteConstant; }
384         |   ShortConstant(context):shortConstant{ return shortConstant; }
385         |   UShortConstant(context):ushortConstant{ return ushortConstant; }
386         |   IntConstant(context):intConstant{ return intConstant; }
387         |   UIntConstant(context):uintConstant{ return uintConstant; }
388         |   LongConstant(context):longConstant{ return longConstant; }
389         |   ULongConstant(context):ulongConstant{ return ulongConstant; }
390         |   FloatConstant(context):floatConstant{ return floatConstant; }
391         |   DoubleConstant(context):doubleConstant{ return doubleConstant; }
392         |   ArrayConstant(context):arrayConstant{ return arrayConstant; }
393         |   StructureConstant(context):structureConstant{ return structureConstant; }
394         |   StringConstant(context):stringConstant{ return stringConstant; }
395         |   StringArrayConstant(context):stringArrayConstant{ return stringArrayConstant; }
396         ;
397 
398     ConversionConstant(cmsx.intermediate.Context* context, var cmsx.intermediate.Type* targetType) : cmsx.intermediate.ConstantValue*
399         ::= (TypeExpr(context):t{ targetType = t; } CONV LPAREN! Constant(context):from! RPAREN!){ return context->MakeConversionValue(targetType, from, span.line); }
400         ;
401 
402     ClsIdConstant(cmsx.intermediate.Context* context, var cmsx.intermediate.Type* type) : cmsx.intermediate.ConstantValue*
403         ::= TypeExpr(context):t{ type = t; } CLSID{ return context->MakeClsIdValue(type, ToUtf8(lexer.GetToken(pos).match.ToString()), span.line); }
404         ;
405 
406     PtrConstant(cmsx.intermediate.Context* context, var cmsx.intermediate.Type* type) : cmsx.intermediate.ConstantValue*
407         ::= (TypeExpr(context):type1{ type = type1; pass = cmsx.intermediate.IsPtrType(type); } NULL){ return cast<cmsx.intermediate.PtrType*>(type)->DefaultValue(); }
408         |   (TypeExpr(context):type2{ type = type2; pass = cmsx.intermediate.IsPtrType(type); } LiteralValue(context, type):literalValue){ return literalValue; }
409         ;
410 
411     SymbolConstant(cmsx.intermediate.Context* context, var cmsx.intermediate.Type* type) : cmsx.intermediate.ConstantValue*
412         ::= TypeExpr(context):t{ type = t; } SymbolValue(context, type):symbolValue{ return symbolValue; }
413         ;
414 
415     BoolConstant(cmsx.intermediate.Context* context) : cmsx.intermediate.ConstantValue*
416         ::= BOOL (TRUE{ return context->GetBoolType()->MakeBoolValue(true); } | FALSE{ return context->GetBoolType()->MakeBoolValue(false); })
417         ;
418 
419     SByteConstant(cmsx.intermediate.Context* context) : cmsx.intermediate.ConstantValue*
420         ::= SBYTE NUMBER{ return context->MakeSByteValue(context->GetSByteType(), ParseSByte(ToUtf8(lexer.GetToken(pos).match.ToString()))); }
421         ;
422 
423     ByteConstant(cmsx.intermediate.Context* context) : cmsx.intermediate.ConstantValue*
424         ::= BYTE NUMBER{ return context->MakeByteValue(context->GetByteType(), ParseByte(ToUtf8(lexer.GetToken(pos).match.ToString()))); }
425         ;
426 
427     ShortConstant(cmsx.intermediate.Context* context) : cmsx.intermediate.ConstantValue*
428         ::= SHORT NUMBER{ return context->MakeShortValue(context->GetShortType(), ParseShort(ToUtf8(lexer.GetToken(pos).match.ToString()))); }
429         ;
430 
431     UShortConstant(cmsx.intermediate.Context* context) : cmsx.intermediate.ConstantValue*
432         ::= USHORT NUMBER{ return context->MakeUShortValue(context->GetUShortType(), ParseUShort(ToUtf8(lexer.GetToken(pos).match.ToString()))); }
433         ;
434 
435     IntConstant(cmsx.intermediate.Context* context) : cmsx.intermediate.ConstantValue*
436         ::= INT NUMBER{ return context->MakeIntValue(context->GetIntType(), ParseInt(ToUtf8(lexer.GetToken(pos).match.ToString()))); }
437         ;
438 
439     UIntConstant(cmsx.intermediate.Context* context) : cmsx.intermediate.ConstantValue*
440         ::= UINT NUMBER{ return context->MakeUIntValue(context->GetUIntType(), ParseUInt(ToUtf8(lexer.GetToken(pos).match.ToString()))); }
441         ;
442 
443     LongConstant(cmsx.intermediate.Context* context) : cmsx.intermediate.ConstantValue*
444         ::= LONG NUMBER{ return context->MakeLongValue(context->GetLongType(), ParseLong(ToUtf8(lexer.GetToken(pos).match.ToString()))); }
445         ;
446 
447     ULongConstant(cmsx.intermediate.Context* context) : cmsx.intermediate.ConstantValue*
448         ::= ULONG NUMBER{ return context->MakeULongValue(context->GetULongType(), ParseULong(ToUtf8(lexer.GetToken(pos).match.ToString()))); }
449         ;
450 
451     FloatConstant(cmsx.intermediate.Context* context) : cmsx.intermediate.ConstantValue*
452         ::= FLOAT NUMBER{ return context->MakeFloatValue(context->GetFloatType(), ParseFloat(ToUtf8(lexer.GetToken(pos).match.ToString()))); }
453         ;
454 
455     DoubleConstant(cmsx.intermediate.Context* context) : cmsx.intermediate.ConstantValue*
456         ::= DOUBLE NUMBER{ return context->MakeDoubleValue(context->GetDoubleType(), ParseDouble(ToUtf8(lexer.GetToken(pos).match.ToString()))); }
457         ;
458 
459     ArrayConstant(cmsx.intermediate.Context* context, var cmsx.intermediate.ArrayValue* value) : cmsx.intermediate.ArrayValue*
460         ::= (LBRACKET{ value = context->MakeArrayValue(); } (Constant(context):element{ value->AddElement(element); } % COMMA)? RBRACKET){ return value; }
461         ;
462 
463     StructureConstant(cmsx.intermediate.Context* context, var cmsx.intermediate.StructureValue* value) : cmsx.intermediate.StructureValue*
464         ::= LBRACE{ value = context->MakeStructureValue(); } (Constant(context):member{ value->AddMember(member); } % COMMA)? RBRACE!{ return value; }
465         ;
466 
467     StringConstant(cmsx.intermediate.Context* context) : cmsx.intermediate.StringValue*
468         ::= STRING{ return context->MakeStringValue(ToUtf8(lexer.GetToken(pos).match.ToString())); }
469         ;
470 
471     StringArrayConstant(cmsx.intermediate.Context* context, var cmsx.intermediate.StringArrayValue* value) : cmsx.intermediate.StringArrayValue*
472         ::= StringArrayPrefix:prefix LBRACKET{ value = context->MakeStringArrayValue(prefix); } (Constant(context):element{ value->AddElement(element); } % COMMA)? RBRACKET{ return value; }
473         ;
474 
475     StringArrayPrefix : char
476         ::= ID{ string p = ToUtf8(lexer.GetToken(pos).match.ToString()); pass = p == "w" || p == "u" || p == "b"; if (pass) return p[0]; }
477         ;
478 
479     Metadata(cmsx.intermediate.Context* context, var cmsx.intermediate.MDStruct* mdStruct)
480         ::= METADATA LBRACE! (MDStruct(context):mds{ mdStruct = mds; })* RBRACE!
481         ;
482 
483     MDItem(cmsx.intermediate.Context* context) : cmsx.intermediate.MDItem*
484         ::= MDBool(context):mdBool{ return mdBool; }
485         |   MDLong(context):mdLong{ return mdLong; }
486         |   MDString(context):mdString{ return mdString; }
487         |   MDStructRef(context):mdStructRef{ return mdStructRef; }
488         ;
489 
490     MDBool(cmsx.intermediate.Context* context) : cmsx.intermediate.MDBool*
491         ::= TRUE{ return context->CreateMDBool(true); }
492         |   FALSE{ return context->CreateMDBool(false); }
493         ;
494 
495     MDLong(cmsx.intermediate.Context* context) : cmsx.intermediate.MDLong*
496         ::= NUMBER{ return context->CreateMDLong(ParseLong(ToUtf8(lexer.GetToken(pos).match.ToString()))); }
497         ;
498 
499     MDString(cmsx.intermediate.Context* context) : cmsx.intermediate.MDString*
500         ::= STRING{ return context->CreateMDString(ToUtf8(lexer.GetToken(pos).match.ToString())); }
501         ;
502 
503     MDStructRef(cmsx.intermediate.Context* context) : cmsx.intermediate.MDStructRef*
504         ::= EXCLAMATION NUMBER{ return context->CreateMDStructRef(ParseInt(ToUtf8(lexer.GetToken(pos).match.ToString()))); }
505         ;
506 
507     MDStruct(cmsx.intermediate.Context* context, var cmsx.intermediate.MDStruct* value) : cmsx.intermediate.MDStruct*
508         ::= (EXCLAMATION NUMBER{ value = context->CreateMDStruct(ParseInt(ToUtf8(lexer.GetToken(pos).match.ToString()))); } ASSIGN LBRACE (MDField(context, value):field % COMMA)? RBRACE){ return value; }
509         ;
510 
511     MDField(cmsx.intermediate.Context* context, cmsx.intermediate.MDStruct* parent, var string fieldName) 
512         ::= (ID{ fieldName = ToUtf8(lexer.GetToken(pos).match.ToString()); } COLON MDItem(context):item){ parent->AddItem(fieldName, item); }
513         ;
514 }