public AbstractProgram Parse() { this.program = new AbstractProgram(); // Process all items in the global scope while (Peek().type != Token.TokenType.EOF) { while (Peek().type == Token.TokenType.Semicolon) { Consume(Token.TokenType.Semicolon); } // For a global object, first token will always be the type Token typeName = Consume(Token.TokenType.TypeName); // Is it a function or a global variable? if (Peek().type == Token.TokenType.VarName) { string newVarName = Consume(Token.TokenType.VarName).content; Variable.VarType newVarType; switch (typeName.content) { case "int": { newVarType = Variable.VarType.Int; } break; case "int*": { newVarType = Variable.VarType.IntPtr; } break; default: { throw new InvalidTypeException(typeName.content); } } int initValue; // Are we initializing with a value? if (Peek().type == Token.TokenType.OpAssign) { Consume(Token.TokenType.OpAssign); // Is it an int or a char? if (Peek().type == Token.TokenType.LiteralChar) { initValue = Consume(Token.TokenType.LiteralChar).content[0]; } else { initValue = int.Parse(Consume(Token.TokenType.LiteralInt).content); } } else { initValue = 0; // Default value is 0 } GlobalVariable newVar = new GlobalVariable { name = newVarName, type = newVarType, initValue = initValue }; program.globalVars.Add(newVar); } else if (Peek().type == Token.TokenType.FuncName) { // typeName : Token - already consumed --> Return Value Variable.VarType returnType; switch (typeName.content) { case "int": { returnType = Variable.VarType.Int; } break; case "int*": { returnType = Variable.VarType.IntPtr; } break; case "void": { returnType = Variable.VarType.Void; } break; default: { throw new InvalidTypeException(typeName.content); } } string newFuncName = Consume(Token.TokenType.FuncName).content; // Now, we need to read the function's arguments List <Variable> newArgs = ParseFunctionSignature(); Consume(Token.TokenType.BraceOpen); // Now, we need the actions/instructions contained in the function! this.currentLocals = new List <Variable>(); this.currentLocals.AddRange(newArgs); List <Action> actions = ParseBlock(); this.program.functions.Add(new Function() { name = newFuncName, returnsValue = returnType, arguments = newArgs, actions = actions, localVars = this.currentLocals }); } else { throw new UnexpectedTokenException(Consume()); } } return(this.program); }
public Emitter(AbstractProgram program) { this.program = program; }
static void Main(string[] args) { System.Console.WriteLine("\nDuke 250/16 C Compiler version 1.0 - Radu Vasilescu, 2019\n"); if (args.Length == 0) { System.Console.WriteLine(); ShowHelpText(); return; } bool verbose = false; bool printPreproc = false; bool enableStrout = true; string sourceFile = ""; foreach (string arg in args) { if (arg == "-v" || arg == "--verbose") { verbose = true; } else if (arg == "-h" || arg == "--help") { ShowHelpText(); Environment.Exit(0); } else if (arg == "-p" || arg == "--pre-processor") { printPreproc = true; } else if (arg == "--disable-strout") { enableStrout = false; } else { sourceFile = arg; } } // Read the source file string[] sourceStr; List <string> source = null; try { sourceStr = File.ReadAllLines(sourceFile); source = sourceStr.OfType <string>().ToList(); } catch (Exception e) { Console.Error.WriteLine("Error: " + e.Message); Environment.Exit(1); } // Run the pre-processor source = Preprocessor.ProcessAll(source, enableStrout); if (printPreproc) { PrintSource(source); } // Tokenize the source Tokenizer toker = new Tokenizer(); List <Token> tokenized = null; try { tokenized = toker.Tokenize(source); } catch (Tokenizer.TokenException e) { Console.Error.WriteLine("Error: " + e.Message); Environment.Exit(1); } if (verbose) { System.Console.WriteLine("Parsing..."); } // Parse the tokenized program into a collection of Abstract Source Trees Parser parser = new Parser(tokenized); AbstractProgram parsedProgram = parser.Parse(); if (verbose) { System.Console.WriteLine("Done parsing."); } // Generate and emit assembly instructions Emitter emitter = new Emitter(parsedProgram); List <string> outputCode = emitter.EmitAssembly(); if (verbose) { System.Console.WriteLine("Done emitting."); } if (verbose) { System.Console.WriteLine("\nAssembly: \n"); foreach (string line in outputCode) { System.Console.WriteLine(line); } } string outputFile = sourceFile.Split(".")[0] + ".s"; string outputCodeStr = String.Join("\n", outputCode); File.WriteAllText(outputFile, outputCodeStr); if (verbose) { System.Console.WriteLine("\nOutput stored in: " + outputFile); } }