Пример #1
0
        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);
        }
Пример #2
0
 public Emitter(AbstractProgram program)
 {
     this.program = program;
 }
Пример #3
0
        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);
            }
        }