//===-- llvmAsmParser.y - Parser for llvm assembly files ---------*- C++ -*--=// // // This file implements the bison parser for LLVM assembly languages files. // //===------------------------------------------------------------------------=// // // TODO: Parse comments and add them to an internal node... so that they may // be saved in the bytecode format as well as everything else. Very important // for a general IR format. // %{ #include "ParserInternals.h" #include "llvm/BasicBlock.h" #include "llvm/Method.h" #include "llvm/SymbolTable.h" #include "llvm/Module.h" #include "llvm/Type.h" #include "llvm/DerivedTypes.h" #include "llvm/Assembly/Parser.h" #include "llvm/ConstantPool.h" #include "llvm/iTerminators.h" #include "llvm/iMemory.h" #include #include // Get definition of pair class #include // This embarasment is due to our flex lexer... int yyerror(char *ErrorMsg); // Forward declarations to prevent "implicit int yylex(); // declaration" of xxx warnings. int yyparse(); static Module *ParserResult; const ToolCommandLine *CurOptions = 0; // This contains info used when building the body of a method. It is destroyed // when the method is completed. // typedef vector ValueList; // Numbered defs static void ResolveDefinitions(vector &LateResolvers); static struct PerModuleInfo { Module *CurrentModule; vector Values; // Module level numbered definitions vector LateResolveValues; void ModuleDone() { // If we could not resolve some blocks at parsing time (forward branches) // resolve the branches now... ResolveDefinitions(LateResolveValues); Values.clear(); // Clear out method local definitions CurrentModule = 0; } } CurModule; static struct PerMethodInfo { Method *CurrentMethod; // Pointer to current method being created vector Values; // Keep track of numbered definitions vector LateResolveValues; inline PerMethodInfo() { CurrentMethod = 0; } inline ~PerMethodInfo() {} inline void MethodStart(Method *M) { CurrentMethod = M; } void MethodDone() { // If we could not resolve some blocks at parsing time (forward branches) // resolve the branches now... ResolveDefinitions(LateResolveValues); Values.clear(); // Clear out method local definitions CurrentMethod = 0; } } CurMeth; // Info for the current method... //===----------------------------------------------------------------------===// // Code to handle definitions of all the types //===----------------------------------------------------------------------===// static void InsertValue(Value *D, vector &ValueTab = CurMeth.Values) { if (!D->hasName()) { // Is this a numbered definition? unsigned type = D->getType()->getUniqueID(); if (ValueTab.size() <= type) ValueTab.resize(type+1, ValueList()); //printf("Values[%d][%d] = %d\n", type, ValueTab[type].size(), D); ValueTab[type].push_back(D); } } static Value *getVal(const Type *Type, ValID &D, bool DoNotImprovise = false) { switch (D.Type) { case 0: { // Is it a numbered definition? unsigned type = Type->getUniqueID(); unsigned Num = (unsigned)D.Num; // Module constants occupy the lowest numbered slots... if (type < CurModule.Values.size()) { if (Num < CurModule.Values[type].size()) return CurModule.Values[type][Num]; Num -= CurModule.Values[type].size(); } // Make sure that our type is within bounds if (CurMeth.Values.size() <= type) break; // Check that the number is within bounds... if (CurMeth.Values[type].size() <= Num) break; return CurMeth.Values[type][Num]; } case 1: { // Is it a named definition? string Name(D.Name); SymbolTable *SymTab = 0; if (CurMeth.CurrentMethod) SymTab = CurMeth.CurrentMethod->getSymbolTable(); Value *N = SymTab ? SymTab->lookup(Type, Name) : 0; if (N == 0) { SymTab = CurModule.CurrentModule->getSymbolTable(); if (SymTab) N = SymTab->lookup(Type, Name); if (N == 0) break; } D.destroy(); // Free old strdup'd memory... return N; } case 2: // Is it a constant pool reference?? case 3: // Is it an unsigned const pool reference? case 4:{ // Is it a string const pool reference? ConstPoolVal *CPV = 0; // Check to make sure that "Type" is an integral type, and that our // value will fit into the specified type... switch (D.Type) { case 2: if (Type == Type::BoolTy) { // Special handling for boolean data CPV = new ConstPoolBool(D.ConstPool64 != 0); } else { if (!ConstPoolSInt::isValueValidForType(Type, D.ConstPool64)) ThrowException("Symbolic constant pool reference is invalid!"); CPV = new ConstPoolSInt(Type, D.ConstPool64); } break; case 3: if (!ConstPoolUInt::isValueValidForType(Type, D.UConstPool64)) { if (!ConstPoolSInt::isValueValidForType(Type, D.ConstPool64)) { ThrowException("Symbolic constant pool reference is invalid!"); } else { // This is really a signed reference. Transmogrify. CPV = new ConstPoolSInt(Type, D.ConstPool64); } } else { CPV = new ConstPoolUInt(Type, D.UConstPool64); } break; case 4: cerr << "FIXME: TODO: String constants [sbyte] not implemented yet!\n"; abort(); //CPV = new ConstPoolString(D.Name); D.destroy(); // Free the string memory break; } assert(CPV && "How did we escape creating a constant??"); // Scan through the constant table and see if we already have loaded this // constant. // ConstantPool &CP = CurMeth.CurrentMethod ? CurMeth.CurrentMethod->getConstantPool() : CurModule.CurrentModule->getConstantPool(); ConstPoolVal *C = CP.find(CPV); // Already have this constant? if (C) { delete CPV; // Didn't need this after all, oh well. return C; // Yup, we already have one, recycle it! } CP.insert(CPV); // Success, everything is kosher. Lets go! return CPV; } // End of case 2,3,4 } // End of switch // If we reached here, we referenced either a symbol that we don't know about // or an id number that hasn't been read yet. We may be referencing something // forward, so just create an entry to be resolved later and get to it... // if (DoNotImprovise) return 0; // Do we just want a null to be returned? // TODO: Attempt to coallecse nodes that are the same with previous ones. Value *d = 0; switch (Type->getPrimitiveID()) { case Type::LabelTyID: d = new BBPlaceHolder(Type, D); break; case Type::MethodTyID: d = new MethPlaceHolder(Type, D); InsertValue(d, CurModule.LateResolveValues); return d; //case Type::ClassTyID: d = new ClassPlaceHolder(Type, D); break; default: d = new DefPlaceHolder(Type, D); break; } assert(d != 0 && "How did we not make something?"); InsertValue(d, CurMeth.LateResolveValues); return d; } //===----------------------------------------------------------------------===// // Code to handle forward references in instructions //===----------------------------------------------------------------------===// // // This code handles the late binding needed with statements that reference // values not defined yet... for example, a forward branch, or the PHI node for // a loop body. // // This keeps a table (CurMeth.LateResolveValues) of all such forward references // and back patchs after we are done. // // ResolveDefinitions - If we could not resolve some defs at parsing // time (forward branches, phi functions for loops, etc...) resolve the // defs now... // static void ResolveDefinitions(vector &LateResolvers) { // Loop over LateResolveDefs fixing up stuff that couldn't be resolved for (unsigned ty = 0; ty < LateResolvers.size(); ty++) { while (!LateResolvers[ty].empty()) { Value *V = LateResolvers[ty].back(); LateResolvers[ty].pop_back(); ValID &DID = getValIDFromPlaceHolder(V); Value *TheRealValue = getVal(Type::getUniqueIDType(ty), DID, true); if (TheRealValue == 0 && DID.Type == 1) ThrowException("Reference to an invalid definition: '" +DID.getName() + "' of type '" + V->getType()->getName() + "'"); else if (TheRealValue == 0) ThrowException("Reference to an invalid definition: #" +itostr(DID.Num)+ " of type '" + V->getType()->getName() + "'"); V->replaceAllUsesWith(TheRealValue); assert(V->use_empty()); delete V; } } LateResolvers.clear(); } // addConstValToConstantPool - This code is used to insert a constant into the // current constant pool. This is designed to make maximal (but not more than // possible) reuse (merging) of constants in the constant pool. This means that // multiple references to %4, for example will all get merged. // static ConstPoolVal *addConstValToConstantPool(ConstPoolVal *C) { vector &ValTab = CurMeth.CurrentMethod ? CurMeth.Values : CurModule.Values; ConstantPool &CP = CurMeth.CurrentMethod ? CurMeth.CurrentMethod->getConstantPool() : CurModule.CurrentModule->getConstantPool(); if (ConstPoolVal *CPV = CP.find(C)) { // Constant already in constant pool. Try to merge the two constants if (CPV->hasName() && !C->hasName()) { // Merge the two values, we inherit the existing CPV's name. // InsertValue requires that the value have no name to insert correctly // (because we want to fill the slot this constant would have filled) // string Name = CPV->getName(); CPV->setName(""); InsertValue(CPV, ValTab); CPV->setName(Name); delete C; return CPV; } else if (!CPV->hasName() && C->hasName()) { // If we have a name on this value and there isn't one in the const // pool val already, propogate it. // CPV->setName(C->getName()); delete C; // Sorry, you're toast return CPV; } else if (CPV->hasName() && C->hasName()) { // Both values have distinct names. We cannot merge them. CP.insert(C); InsertValue(C, ValTab); return C; } else if (!CPV->hasName() && !C->hasName()) { // Neither value has a name, trivially merge them. InsertValue(CPV, ValTab); delete C; return CPV; } assert(0 && "Not reached!"); return 0; } else { // No duplication of value. CP.insert(C); InsertValue(C, ValTab); return C; } } //===----------------------------------------------------------------------===// // RunVMAsmParser - Define an interface to this parser //===----------------------------------------------------------------------===// // Module *RunVMAsmParser(const ToolCommandLine &Opts, FILE *F) { llvmAsmin = F; CurOptions = &Opts; llvmAsmlineno = 1; // Reset the current line number... CurModule.CurrentModule = new Module(); // Allocate a new module to read yyparse(); // Parse the file. Module *Result = ParserResult; CurOptions = 0; llvmAsmin = stdin; // F is about to go away, don't use it anymore... ParserResult = 0; return Result; } %} %union { Module *ModuleVal; Method *MethodVal; MethodArgument *MethArgVal; BasicBlock *BasicBlockVal; TerminatorInst *TermInstVal; Instruction *InstVal; ConstPoolVal *ConstVal; const Type *TypeVal; list *MethodArgList; list *ValueList; list *TypeList; list > *JumpTable; vector *ConstVector; int64_t SInt64Val; uint64_t UInt64Val; int SIntVal; unsigned UIntVal; char *StrVal; // This memory is allocated by strdup! ValID ValIDVal; // May contain memory allocated by strdup Instruction::UnaryOps UnaryOpVal; Instruction::BinaryOps BinaryOpVal; Instruction::TermOps TermOpVal; Instruction::MemoryOps MemOpVal; } %type Module MethodList %type Method MethodHeader BasicBlockList %type BasicBlock InstructionList %type BBTerminatorInst %type Inst InstVal MemoryInst %type ConstVal %type ConstVector %type ArgList ArgListH %type ArgVal %type ValueRefList ValueRefListE %type TypeList %type JumpTable %type ValueRef ConstValueRef // Reference to a definition or BB // Tokens and types for handling constant integer values // // ESINT64VAL - A negative number within long long range %token ESINT64VAL // EUINT64VAL - A positive number within uns. long long range %token EUINT64VAL %type EINT64VAL %token SINTVAL // Signed 32 bit ints... %token UINTVAL // Unsigned 32 bit ints... %type INTVAL // Built in types... %type Types TypesV SIntType UIntType IntType %token VOID BOOL SBYTE UBYTE SHORT USHORT INT UINT LONG ULONG %token FLOAT DOUBLE STRING TYPE LABEL %token VAR_ID LABELSTR STRINGCONSTANT %type OptVAR_ID OptAssign %token IMPLEMENTATION TRUE FALSE BEGINTOK END DECLARE %token PHI CALL // Basic Block Terminating Operators %token RET BR SWITCH // Unary Operators %type UnaryOps // all the unary operators %token NEG NOT // Unary Conversion Operators %token TOINT TOUINT // Binary Operators %type BinaryOps // all the binary operators %token ADD SUB MUL DIV REM // Binary Comarators %token SETLE SETGE SETLT SETGT SETEQ SETNE // Memory Instructions %token MALLOC ALLOCA FREE LOAD STORE GETFIELD PUTFIELD %start Module %% // Handle constant integer size restriction and conversion... // INTVAL : SINTVAL INTVAL : UINTVAL { if ($1 > (uint32_t)INT32_MAX) // Outside of my range! ThrowException("Value too large for type!"); $$ = (int32_t)$1; } EINT64VAL : ESINT64VAL // These have same type and can't cause problems... EINT64VAL : EUINT64VAL { if ($1 > (uint64_t)INT64_MAX) // Outside of my range! ThrowException("Value too large for type!"); $$ = (int64_t)$1; } // Types includes all predefined types... except void, because you can't do // anything with it except for certain specific things... // // User defined types are added latter... // Types : BOOL | SBYTE | UBYTE | SHORT | USHORT | INT | UINT Types : LONG | ULONG | FLOAT | DOUBLE | STRING | TYPE | LABEL // TypesV includes all of 'Types', but it also includes the void type. TypesV : Types | VOID // Operations that are notably excluded from this list include: // RET, BR, & SWITCH because they end basic blocks and are treated specially. // UnaryOps : NEG | NOT | TOINT | TOUINT BinaryOps : ADD | SUB | MUL | DIV | REM BinaryOps : SETLE | SETGE | SETLT | SETGT | SETEQ | SETNE // Valueine some types that allow classification if we only want a particular // thing... SIntType : LONG | INT | SHORT | SBYTE UIntType : ULONG | UINT | USHORT | UBYTE IntType : SIntType | UIntType OptAssign : VAR_ID '=' { $$ = $1; } | /*empty*/ { $$ = 0; } ConstVal : SIntType EINT64VAL { // integral constants if (!ConstPoolSInt::isValueValidForType($1, $2)) ThrowException("Constant value doesn't fit in type!"); $$ = new ConstPoolSInt($1, $2); } | UIntType EUINT64VAL { // integral constants if (!ConstPoolUInt::isValueValidForType($1, $2)) ThrowException("Constant value doesn't fit in type!"); $$ = new ConstPoolUInt($1, $2); } | BOOL TRUE { // Boolean constants $$ = new ConstPoolBool(true); } | BOOL FALSE { // Boolean constants $$ = new ConstPoolBool(false); } | STRING STRINGCONSTANT { // String constants cerr << "FIXME: TODO: String constants [sbyte] not implemented yet!\n"; abort(); //$$ = new ConstPoolString($2); free($2); } | TYPE Types { // Type constants $$ = new ConstPoolType($2); } | '[' Types ']' '[' ConstVector ']' { // Nonempty array constant // Verify all elements are correct type! const ArrayType *AT = ArrayType::getArrayType($2); for (unsigned i = 0; i < $5->size(); i++) { if ($2 != (*$5)[i]->getType()) ThrowException("Element #" + utostr(i) + " is not of type '" + $2->getName() + "' as required!\nIt is of type '" + (*$5)[i]->getType()->getName() + "'."); } $$ = new ConstPoolArray(AT, *$5); delete $5; } | '[' Types ']' '[' ']' { // Empty array constant vector Empty; $$ = new ConstPoolArray(ArrayType::getArrayType($2), Empty); } | '[' EUINT64VAL 'x' Types ']' '[' ConstVector ']' { // Verify all elements are correct type! const ArrayType *AT = ArrayType::getArrayType($4, (int)$2); if ($2 != $7->size()) ThrowException("Type mismatch: constant sized array initialized with " + utostr($7->size()) + " arguments, but has size of " + itostr((int)$2) + "!"); for (unsigned i = 0; i < $7->size(); i++) { if ($4 != (*$7)[i]->getType()) ThrowException("Element #" + utostr(i) + " is not of type '" + $4->getName() + "' as required!\nIt is of type '" + (*$7)[i]->getType()->getName() + "'."); } $$ = new ConstPoolArray(AT, *$7); delete $7; } | '[' EUINT64VAL 'x' Types ']' '[' ']' { if ($2 != 0) ThrowException("Type mismatch: constant sized array initialized with 0" " arguments, but has size of " + itostr((int)$2) + "!"); vector Empty; $$ = new ConstPoolArray(ArrayType::getArrayType($4, 0), Empty); } | '{' TypeList '}' '{' ConstVector '}' { StructType::ElementTypes Types($2->begin(), $2->end()); delete $2; const StructType *St = StructType::getStructType(Types); $$ = new ConstPoolStruct(St, *$5); delete $5; } | '{' '}' '{' '}' { const StructType *St = StructType::getStructType(StructType::ElementTypes()); vector Empty; $$ = new ConstPoolStruct(St, Empty); } /* | Types '*' ConstVal { assert(0); $$ = 0; } */ ConstVector : ConstVector ',' ConstVal { ($$ = $1)->push_back(addConstValToConstantPool($3)); } | ConstVal { $$ = new vector(); $$->push_back(addConstValToConstantPool($1)); } ConstPool : ConstPool OptAssign ConstVal { if ($2) { $3->setName($2); free($2); } addConstValToConstantPool($3); } | /* empty: end of list */ { } //===----------------------------------------------------------------------===// // Rules to match Modules //===----------------------------------------------------------------------===// // Module rule: Capture the result of parsing the whole file into a result // variable... // Module : MethodList { $$ = ParserResult = $1; CurModule.ModuleDone(); } MethodList : MethodList Method { $1->getMethodList().push_back($2); CurMeth.MethodDone(); $$ = $1; } | ConstPool IMPLEMENTATION { $$ = CurModule.CurrentModule; } //===----------------------------------------------------------------------===// // Rules to match Method Headers //===----------------------------------------------------------------------===// OptVAR_ID : VAR_ID | /*empty*/ { $$ = 0; } ArgVal : Types OptVAR_ID { $$ = new MethodArgument($1); if ($2) { // Was the argument named? $$->setName($2); free($2); // The string was strdup'd, so free it now. } } ArgListH : ArgVal ',' ArgListH { $$ = $3; $3->push_front($1); } | ArgVal { $$ = new list(); $$->push_front($1); } ArgList : ArgListH { $$ = $1; } | /* empty */ { $$ = 0; } MethodHeaderH : TypesV STRINGCONSTANT '(' ArgList ')' { MethodType::ParamTypes ParamTypeList; if ($4) for (list::iterator I = $4->begin(); I != $4->end(); I++) ParamTypeList.push_back((*I)->getType()); const MethodType *MT = MethodType::getMethodType($1, ParamTypeList); Method *M = new Method(MT, $2); free($2); // Free strdup'd memory! InsertValue(M, CurModule.Values); CurMeth.MethodStart(M); // Add all of the arguments we parsed to the method... if ($4) { // Is null if empty... Method::ArgumentListType &ArgList = M->getArgumentList(); for (list::iterator I = $4->begin(); I != $4->end(); I++) { InsertValue(*I); ArgList.push_back(*I); } delete $4; // We're now done with the argument list } } MethodHeader : MethodHeaderH ConstPool BEGINTOK { $$ = CurMeth.CurrentMethod; } Method : BasicBlockList END { $$ = $1; } //===----------------------------------------------------------------------===// // Rules to match Basic Blocks //===----------------------------------------------------------------------===// ConstValueRef : ESINT64VAL { // A reference to a direct constant $$ = ValID::create($1); } | EUINT64VAL { $$ = ValID::create($1); } | TRUE { $$ = ValID::create((int64_t)1); } | FALSE { $$ = ValID::create((int64_t)0); } | STRINGCONSTANT { // Quoted strings work too... especially for methods $$ = ValID::create_conststr($1); } // ValueRef - A reference to a definition... ValueRef : INTVAL { // Is it an integer reference...? $$ = ValID::create($1); } | VAR_ID { // It must be a named reference then... $$ = ValID::create($1); } | ConstValueRef { $$ = $1; } // The user may refer to a user defined type by its typeplane... check for this // now... // Types : ValueRef { Value *D = getVal(Type::TypeTy, $1, true); if (D == 0) ThrowException("Invalid user defined type: " + $1.getName()); assert (D->getValueType() == Value::ConstantVal && "Internal error! User defined type not in const pool!"); ConstPoolType *CPT = (ConstPoolType*)D; $$ = CPT->getValue(); } | TypesV '(' TypeList ')' { // Method derived type? MethodType::ParamTypes Params($3->begin(), $3->end()); delete $3; $$ = MethodType::getMethodType($1, Params); } | TypesV '(' ')' { // Method derived type? MethodType::ParamTypes Params; // Empty list $$ = MethodType::getMethodType($1, Params); } | '[' Types ']' { $$ = ArrayType::getArrayType($2); } | '[' EUINT64VAL 'x' Types ']' { $$ = ArrayType::getArrayType($4, (int)$2); } | '{' TypeList '}' { StructType::ElementTypes Elements($2->begin(), $2->end()); delete $2; $$ = StructType::getStructType(Elements); } | '{' '}' { $$ = StructType::getStructType(StructType::ElementTypes()); } | Types '*' { $$ = PointerType::getPointerType($1); } TypeList : Types { $$ = new list(); $$->push_back($1); } | TypeList ',' Types { ($$=$1)->push_back($3); } BasicBlockList : BasicBlockList BasicBlock { $1->getBasicBlocks().push_back($2); $$ = $1; } | MethodHeader BasicBlock { // Do not allow methods with 0 basic blocks $$ = $1; // in them... $1->getBasicBlocks().push_back($2); } // Basic blocks are terminated by branching instructions: // br, br/cc, switch, ret // BasicBlock : InstructionList BBTerminatorInst { $1->getInstList().push_back($2); InsertValue($1); $$ = $1; } | LABELSTR InstructionList BBTerminatorInst { $2->getInstList().push_back($3); $2->setName($1); free($1); // Free the strdup'd memory... InsertValue($2); $$ = $2; } InstructionList : InstructionList Inst { $1->getInstList().push_back($2); $$ = $1; } | /* empty */ { $$ = new BasicBlock(); } BBTerminatorInst : RET Types ValueRef { // Return with a result... $$ = new ReturnInst(getVal($2, $3)); } | RET VOID { // Return with no result... $$ = new ReturnInst(); } | BR LABEL ValueRef { // Unconditional Branch... $$ = new BranchInst((BasicBlock*)getVal(Type::LabelTy, $3)); } // Conditional Branch... | BR BOOL ValueRef ',' LABEL ValueRef ',' LABEL ValueRef { $$ = new BranchInst((BasicBlock*)getVal(Type::LabelTy, $6), (BasicBlock*)getVal(Type::LabelTy, $9), getVal(Type::BoolTy, $3)); } | SWITCH IntType ValueRef ',' LABEL ValueRef '[' JumpTable ']' { SwitchInst *S = new SwitchInst(getVal($2, $3), (BasicBlock*)getVal(Type::LabelTy, $6)); $$ = S; list >::iterator I = $8->begin(), end = $8->end(); for (; I != end; I++) S->dest_push_back(I->first, I->second); } JumpTable : JumpTable IntType ConstValueRef ',' LABEL ValueRef { $$ = $1; ConstPoolVal *V = (ConstPoolVal*)getVal($2, $3, true); if (V == 0) ThrowException("May only switch on a constant pool value!"); $$->push_back(make_pair(V, (BasicBlock*)getVal($5, $6))); } | IntType ConstValueRef ',' LABEL ValueRef { $$ = new list >(); ConstPoolVal *V = (ConstPoolVal*)getVal($1, $2, true); if (V == 0) ThrowException("May only switch on a constant pool value!"); $$->push_back(make_pair(V, (BasicBlock*)getVal($4, $5))); } Inst : OptAssign InstVal { if ($1) // Is this definition named?? $2->setName($1); // if so, assign the name... InsertValue($2); $$ = $2; } ValueRefList : Types ValueRef { // Used for PHI nodes and call statements... $$ = new list(); $$->push_back(getVal($1, $2)); } | ValueRefList ',' ValueRef { $$ = $1; $1->push_back(getVal($1->front()->getType(), $3)); } // ValueRefListE - Just like ValueRefList, except that it may also be empty! ValueRefListE : ValueRefList | /*empty*/ { $$ = 0; } InstVal : BinaryOps Types ValueRef ',' ValueRef { $$ = Instruction::getBinaryOperator($1, getVal($2, $3), getVal($2, $5)); if ($$ == 0) ThrowException("binary operator returned null!"); } | UnaryOps Types ValueRef { $$ = Instruction::getUnaryOperator($1, getVal($2, $3)); if ($$ == 0) ThrowException("unary operator returned null!"); } | PHI ValueRefList { $$ = new PHINode($2->front()->getType()); while ($2->begin() != $2->end()) { // TODO: Ensure all types are the same... ((PHINode*)$$)->addIncoming($2->front()); $2->pop_front(); } delete $2; // Free the list... } | CALL Types ValueRef '(' ValueRefListE ')' { if (!$2->isMethodType()) ThrowException("Can only call methods: invalid type '" + $2->getName() + "'!"); const MethodType *Ty = (const MethodType*)$2; Value *V = getVal(Ty, $3); if (V->getValueType() != Value::MethodVal || V->getType() != Ty) ThrowException("Cannot call: " + $3.getName() + "!"); // Create or access a new type that corresponds to the function call... vector Params; if ($5) { // Pull out just the arguments... Params.insert(Params.begin(), $5->begin(), $5->end()); delete $5; // Loop through MethodType's arguments and ensure they are specified // correctly! // MethodType::ParamTypes::const_iterator I = Ty->getParamTypes().begin(); unsigned i; for (i = 0; i < Params.size() && I != Ty->getParamTypes().end(); ++i,++I){ if (Params[i]->getType() != *I) ThrowException("Parameter " + utostr(i) + " is not of type '" + (*I)->getName() + "'!"); } if (i != Params.size() || I != Ty->getParamTypes().end()) ThrowException("Invalid number of parameters detected!"); } // Create the call node... $$ = new CallInst((Method*)V, Params); } | MemoryInst { $$ = $1; } MemoryInst : MALLOC Types { ConstPoolVal *TyVal = new ConstPoolType(PointerType::getPointerType($2)); TyVal = addConstValToConstantPool(TyVal); $$ = new MallocInst((ConstPoolType*)TyVal); } | MALLOC Types ',' UINT ValueRef { if (!$2->isArrayType() || ((const ArrayType*)$2)->isSized()) ThrowException("Trying to allocate " + $2->getName() + " as unsized array!"); Value *ArrSize = getVal($4, $5); ConstPoolVal *TyVal = new ConstPoolType(PointerType::getPointerType($2)); TyVal = addConstValToConstantPool(TyVal); $$ = new MallocInst((ConstPoolType*)TyVal, ArrSize); } | ALLOCA Types { ConstPoolVal *TyVal = new ConstPoolType(PointerType::getPointerType($2)); TyVal = addConstValToConstantPool(TyVal); $$ = new AllocaInst((ConstPoolType*)TyVal); } | ALLOCA Types ',' UINT ValueRef { if (!$2->isArrayType() || ((const ArrayType*)$2)->isSized()) ThrowException("Trying to allocate " + $2->getName() + " as unsized array!"); Value *ArrSize = getVal($4, $5); ConstPoolVal *TyVal = new ConstPoolType(PointerType::getPointerType($2)); TyVal = addConstValToConstantPool(TyVal); $$ = new AllocaInst((ConstPoolType*)TyVal, ArrSize); } | FREE Types ValueRef { if (!$2->isPointerType()) ThrowException("Trying to free nonpointer type " + $2->getName() + "!"); $$ = new FreeInst(getVal($2, $3)); } %% int yyerror(char *ErrorMsg) { ThrowException(string("Parse error: ") + ErrorMsg); return 0; }