public static void EndCompoundStatement(List <CCompoundStatmentItemType> itemTypes) { CIdentifier.ExitBlockScope(); List <CStatment> blockBody = new List <CStatment>(); List <int> localVarSizes = new List <int>(); //the item types come in sequential order (top to bottom), but they are sitting on the stack in reverse order (botom to top) //revers the list to deal with this itemTypes.Reverse(); foreach (var itemType in itemTypes) { if (itemType == CCompoundStatmentItemType.Statment) { CStatment stat = PopStatement(); blockBody.Add(stat); } else { CDeclaration decl = CDeclaration.PopDecl(); localVarSizes.Add(decl.Size); //get a statments that initilizes the local variable (or does nothing if it is not a definition) blockBody.Add(decl.GetDefinitionStatment()); } } //put the statments back in top to bottom order blockBody.Reverse(); PushStatement(new CStatment(blockBody, localVarSizes)); }
internal static CIdentifier InternString(string p) { string name = AutoGenerateLabel("internedString"); var id = new CIdentifier(name, p); fileScope[name] = id; return(id); }
//if statment public CStatment(CExpression cExpression, CStatment cStatment) { string ifBody = CIdentifier.AutoGenerateLabel("ifBody"); string EndIf = CIdentifier.AutoGenerateLabel("endIf"); Add(cExpression); Add(new OpCodeEmitter(OpCode.PUSHW, ifBody)); Add(new OpCodeEmitter(OpCode.JIF)); Add(new OpCodeEmitter(OpCode.PUSHW, EndIf)); Add(new OpCodeEmitter(OpCode.JMP)); Add(new LabelEmitter(ifBody)); Add(cStatment); Add(new LabelEmitter(EndIf)); }
//exit function scope public static void EndFunctionDefinition(int numSpecifiers) { CIdentifier.ExitFunctionScope(); List <CDeclarationSpecifier> specs = new List <CDeclarationSpecifier>(); for (int i = 0; i < numSpecifiers; i++) { specs.Add(PopDeclSpec()); } CDeclarationSpecifier typeSpec = specs.First(spec => spec.SpeciferType == CDeclarationSpecifierType.Type); CDeclarationSpecifier storageClass = specs.FirstOrDefault(spec => spec.SpeciferType == CDeclarationSpecifierType.Storage); CDeclarator paramDecl = PopDeclarator(); CIdentifier.DefineFunction(paramDecl.TypeModifier.ModifyType(typeSpec.type), paramDecl.Identifer, storageClass == null ? CStorageClass.Ignore : storageClass.StorageClass); }
//paramaters //define param in function scope or function prototype scope public static void ParamaterDeclaration(int numSpecifiers) { List <CDeclarationSpecifier> specs = new List <CDeclarationSpecifier>(); for (int i = 0; i < numSpecifiers; i++) { specs.Add(PopDeclSpec()); } CDeclarationSpecifier typeSpec = specs.First(spec => spec.SpeciferType == CDeclarationSpecifierType.Type); //ignore const and register specifiers on params CDeclarator declarator = PopDeclarator(); CParamater param = CIdentifier.CreateFunctionParameter( declarator.Identifer, declarator.TypeModifier != null ? declarator.TypeModifier.ModifyType(typeSpec.type) : typeSpec.type ); PushParam(param); }
internal static CIdentifier CreatLabel(string label) { CIdentifier lb = new CIdentifier(label); if (currentFunctionScope != null) { if (currentFunctionScope.ContainsKey(label)) { throw new SemanticException("label " + label + " already exists in this scope"); } currentFunctionScope[label] = lb; } else { if (fileScope.ContainsKey(label)) { throw new SemanticException("label " + label + " already exists in this scope"); } fileScope[label] = lb; } return(lb); }
//parameter list //enter function prototype scope public static void BeginFunctionDeclarator() { CIdentifier.EnterFunctionPrototypeScope(); }
//definitions //A definition is a declaration that provides all information about the identifiers it declares. //Every declaration of an enum or a typedef is a definition. //For functions, a declaration that includes the function body is a function definition: //For objects, a declaration that allocates storage (automatic or static, but not extern) is a definition, //while a declaration that does not allocate storage (external declaration) is not. //For structs, declarations that specify the list of members are definitions: //declarations which are not definitions can be repeted. declarations which are definitions cannot be repeted //http://en.cppreference.com/w/c/language/function_definition //Unlike function declaration, function definitions are allowed at file scope only (there are no nested functions). // functions are of the form // specifiers-and-qualifiers parameter-list-declarator function-body /* * specifiers-and-qualifiers - a combination of * type specifiers that, possibly modified by the declarator, form the return type * storage class specifiers, which determine the linkage of the identifier (static, extern, or none) * * parameter-list-declarator - a declarator for a function type which uses a parameter list to designate function parameters * * function-body - a compound statement, that is a brace-enclosed sequence of declarations and statements, that is executed whenever this function is called * * return type of function must be a complete non-array object type or the type void. */ //enter function scope public static void BeginFunctionDefinition() { CIdentifier.EnterFunctionScope(); }
//storage and linkage //http://en.cppreference.com/w/c/language/storage_duration /* * Every object has a property called storage duration, which limits the object lifetime. There are four kinds of storage duration in C: * * automatic storage duration. * The storage is allocated when the block in which the object was declared is entered and * deallocated when it is exited by any means (goto, return, reaching the end). If the block is entered recursively, a new allocation is performed for every recursion level. All function parameters and non-static block-scope objects have this storage duration. * * static storage duration. * The storage duration is the entire execution of the program, * and the value stored in the object is initialized only once, prior to main function. * All objects declared static and all objects with either internal or external linkage have this storage duration. * * thread storage duration. NOT SUPPORTED * * allocated storage duration. * The storage is allocated and deallocated on request, using dynamic memory allocation functions. * * Linkage * Linkage refers to the ability of an identifier (variable or function) to be referred to in other scopes. * If a variable or function with the same identifier is declared in several scopes, * but cannot be referred to from all of them, then several instances of the variable are generated. * * The following linkages are recognized: * * no linkage. * The identifier can be referred to only from the scope it is in. * All function parameters and all non-extern block-scope variables (including the ones declared static) have this linkage. * * internal linkage. * The identifier can be referred to from all scopes in the current translation unit. * All static identifiers (both functions and variables) have this linkage. * * external linkage. * The identifier can be referred to from any other translation units in the entire program. * All non-static functions, all extern variables (unless earlier declared static), and all file-scope non-static variables have this linkage. * * Names at file scope that are const and not extern have external linkage in C * * Storage-class specifiers specify one of the following combinations of storage duration and linkage * auto - automatic duration and no linkage (on stack) * register - NOT SUPPORTED * static - static duration and internal linkage (unless at block scope) (in data or rodata segment) * extern - static duration and external linkage (unless already declared internal) (on heap) * * If no storage-class specifier is provided, the defaults are: * extern for all functions * extern for objects at file scope * auto for objects at block scope * * For any struct or union declared with a storage-class specifier, * the storage duration (but not linkage) applies to their members, recursively. * * Function declarations at block scope can use extern or none at all. * Function declarations at file scope can use extern or static. */ //scope //http://en.cppreference.com/w/c/language/scope /*Each identifier that appears in a C program is visible (that is, may be used) only in some possibly discontiguous portion of the source code called its scope. * Within a scope, an identifier may designate more than one entity only if the entities are in different name spaces. * C has four kinds of scopes: * block scope * file scope * function scope * function prototype scope * * Nested scopes * If two different entities named by the same identifier are in scope at the same time, * and the scopes are nested, * the declaration that appears in the inner scope hides the declaration that appears in the outer scope * * Block Scope * The scope of any identifier declared inside a compound statement, * including function bodies, * or in any expression, declaration, or statement appearing in * if, switch, for, while, or do-while statement, * or within the parameter list of a function definition * begins at the point of declaration and ends at the end of the block or statement in which it was declared. * * File scope * The scope of any identifier declared outside of any block or parameter list begins at the point of declaration and ends at the end of the translation unit (file). * File-scope identifiers have external linkage and static storage duration by default. * * Function scope * A label (and only a label) declared inside a function is in scope everywhere in that function, in all nested blocks, before and after its own declaration. * * Function prototype scope * The scope of a name introduced in the parameter list of a function declaration ends at the end of the function declarator. */ //declarations //http://en.cppreference.com/w/c/language/declarations //A declaration is a C language construct that introduces one or more identifiers into the program and specifies their meaning and properties. //Declarations may appear in any scope. Each declaration ends with a semicolon (just like a statement) and consists of two distinct parts: /* * specifiers-and-qualifiers - whitespace-separated list of, in any order, * exactly one type specifier: * void * the name of an arithmetic type * the name of an atomic type * a name earlier introduced by a typedef declaration * struct, union, or enum specifier * zero or one storage-class specifiers: * typedef, * auto, * static, * extern * optional const * * declarators-and-initializers - comma-separated list of declarators * (each declarator provides additional type information and/or the identifier to declare). * Declarators may be accompanied by initializers. */ public static void Declaration(int numSpecifier, int numDeclarators) { List <CDeclarationSpecifier> specifiers = new List <CDeclarationSpecifier>(); for (int i = 0; i < numSpecifier; i++) { specifiers.Add(PopDeclSpec()); } //TODO hanldle unsigned, signed, long, typedef name IEnumerable <CDeclarationSpecifier> typeSpecs = specifiers.Where(spec => spec.SpeciferType == CDeclarationSpecifierType.Type); CType resolvedType = CType.ResolveTypeFromSpecifers(typeSpecs); IEnumerable <CDeclarationSpecifier> typeDefNames = specifiers.Where(spec => spec.SpeciferType == CDeclarationSpecifierType.Name); CDeclarationSpecifier storageClass = specifiers.FirstOrDefault(spec => spec.SpeciferType == CDeclarationSpecifierType.Storage); CDeclarationSpecifier constQualifier = specifiers.FirstOrDefault(spec => spec.SpeciferType == CDeclarationSpecifierType.Const); List <CDeclarator> declarators = new List <CDeclarator>(); for (int i = 0; i < numDeclarators; i++) { declarators.Add(PopDeclarator()); } List <CIdentifier> declared = new List <CIdentifier>(); foreach (CDeclarator declarator in declarators) { CIdentifier id = CIdentifier.CreateIdentifierInCurrentScope(declarator.Identifer, declarator.TypeModifier != null ? declarator.TypeModifier.ModifyType(resolvedType) : resolvedType, storageClass == null ? CStorageClass.Ignore : storageClass.StorageClass, constQualifier == null ? CConstType.Ignore : constQualifier.ConstType); if (declarator.Init != null) { id.Init = declarator.Init; } declared.Add(id); } if (declared.Count == 0) { if (storageClass != null && storageClass.StorageClass == CStorageClass.Typedef) { //this is a typedef foreach (var defSpec in typeDefNames) { CType.TypeDef(defSpec.name, resolvedType); } } else { //this is a declaration without a declarator var name = typeDefNames.First(); CIdentifier id = CIdentifier.CreateIdentifierInCurrentScope(name.name, resolvedType, storageClass == null ? CStorageClass.Ignore : storageClass.StorageClass, constQualifier == null ? CConstType.Ignore : constQualifier.ConstType); declared.Add(id); } } PushDecl(new CDeclaration(declared)); }
//http://en.cppreference.com/w/c/language/goto // Transfers control unconditionally to the desired location defined by a label. // goto label ; public static void GotoStatement(string label) { CIdentifier id = CIdentifier.IdentifierFromNameInCurrentScope(label); PushStatement(new CStatment(id)); }
private static void EnterLoop() { loopChechLabels.Push(CIdentifier.CreatLabel(CIdentifier.AutoGenerateLabel("LoopCheck"))); loopBodyLabels.Push(CIdentifier.CreatLabel(CIdentifier.AutoGenerateLabel("LoopBody"))); endLoopLabels.Push(CIdentifier.CreatLabel(CIdentifier.AutoGenerateLabel("EndLoop"))); }
//A compound statement, or block, is a brace-enclosed sequence of statements and declarations. //The compound statement allows a set of declarations and statements to be grouped into one unit that can be used // anywhere a single statement is expected (for example, in an if statement or an iteration statement) //Each compound statement introduces its own block scope. //http://en.cppreference.com/w/c/language/scope public static void BeginCompoundStatement() { CIdentifier.EnterBlockScope(); }
//goto statment public CStatment(CIdentifier id) { Add(new OpCodeEmitter(OpCode.PUSHW, id.Name)); Add(new OpCodeEmitter(OpCode.JMP)); }