Exemple #1
0
        Executable CompileExecutable()
        {
            var exe        = new Executable(options.MachineInfo);
            var exeContext = new ExecutableContext(exe, options.Report);

            // Put something at the zero address so we don't get 0 addresses of globals
            exe.AddGlobal("__zero__", CBasicType.SignedInt);

            //
            // Find Variables, Functions, Types
            //
            var exeInitBody = new Block(VariableScope.Local);
            var tucs        = tus.Select(x => new TranslationUnitContext(x, exeContext));
            var tuInits     = new List <(CompiledFunction, EmitContext)> ();

            foreach (var tuc in tucs)
            {
                var tu = tuc.TranslationUnit;
                AddStatementDeclarations(tuc);
                if (tu.InitStatements.Count > 0)
                {
                    var tuInitBody = new Block(VariableScope.Local);
                    tuInitBody.AddStatements(tu.InitStatements);
                    var tuInit = new CompiledFunction($"__{tu.Name}__cinit", CFunctionType.VoidProcedure, tuInitBody);
                    exeInitBody.AddStatement(new ExpressionStatement(new FuncallExpression(new VariableExpression(tuInit.Name, Location.Null, Location.Null))));
                    tuInits.Add((tuInit, tuc));
                    exe.Functions.Add(tuInit);
                }
            }

            //
            // Generate a function to init globals
            //
            var exeInit = new CompiledFunction($"__cinit", CFunctionType.VoidProcedure, exeInitBody);

            exe.Functions.Add(exeInit);

            //
            // Link everything together
            // This is done before compilation to make sure everything is visible (for recursion)
            //
            var functionsToCompile = new List <(CompiledFunction, EmitContext)> {
                (exeInit, exeContext)
            };

            functionsToCompile.AddRange(tuInits);
            foreach (var tuc in tucs)
            {
                var tu = tuc.TranslationUnit;
                foreach (var g in tu.Variables)
                {
                    var v = exe.AddGlobal(g.Name, g.VariableType);
                    v.InitialValue = g.InitialValue;
                }
                var funcs = tu.Functions.Where(x => x.Body != null).ToList();
                exe.Functions.AddRange(funcs);
                functionsToCompile.AddRange(funcs.Select(x => (x, (EmitContext)tuc)));
            }

            //
            // Compile functions
            //
            foreach (var(f, pc) in functionsToCompile)
            {
                var body = f.Body;
                if (body == null)
                {
                    continue;
                }
                var fc = new FunctionContext(exe, f, pc);
                AddStatementDeclarations(fc);
                body.Emit(fc);
                f.LocalVariables.AddRange(fc.LocalVariables);

                // Make sure it returns
                if (body.Statements.Count == 0 || !body.AlwaysReturns)
                {
                    if (f.FunctionType.ReturnType.IsVoid)
                    {
                        fc.Emit(OpCode.Return);
                    }
                    else
                    {
                        options.Report.Error(161, "'" + f.Name + "' not all code paths return a value");
                    }
                }
            }

            return(exe);
        }

        void AddStatementDeclarations(BlockContext context)
        {
            var block = context.Block;

            foreach (var s in block.Statements)
            {
                AddStatementDeclarations(s, context);
            }
        }

        void AddStatementDeclarations(Statement statement, BlockContext context)
        {
            var block = context.Block;

            if (statement is MultiDeclaratorStatement multi)
            {
                if (multi.InitDeclarators != null)
                {
                    foreach (var idecl in multi.InitDeclarators)
                    {
                        if ((multi.Specifiers.StorageClassSpecifier & StorageClassSpecifier.Typedef) != 0)
                        {
                            var name  = idecl.Declarator.DeclaredIdentifier;
                            var ttype = context.MakeCType(multi.Specifiers, idecl.Declarator, idecl.Initializer, block);
                            block.Typedefs[name] = ttype;
                        }
                        else
                        {
                            CType ctype = context.MakeCType(multi.Specifiers, idecl.Declarator, idecl.Initializer, block);
                            var   name  = idecl.Declarator.DeclaredIdentifier;

                            if (ctype is CFunctionType ftype && !HasStronglyBoundPointer(idecl.Declarator))
                            {
                                var nameContext = (idecl.Declarator.InnerDeclarator is IdentifierDeclarator ndecl && ndecl.Context.Count > 0) ?
                                                  string.Join("::", ndecl.Context) : "";
                                var f = new CompiledFunction(name, nameContext, ftype);
                                block.Functions.Add(f);
                            }
                            else
                            {
                                if ((ctype is CArrayType atype) &&
                                    (atype.Length == null) &&
                                    (idecl.Initializer != null))
                                {
                                    if (idecl.Initializer is StructuredInitializer structInit)
                                    {
                                        var len = 0;
                                        foreach (var i in structInit.Initializers)
                                        {
                                            if (i.Designation == null)
                                            {
                                                len++;
                                            }
                                            else
                                            {
                                                foreach (var de in i.Designation.Designators)
                                                {
                                                    // TODO: Pay attention to designators
                                                    len++;
                                                }
                                            }
                                        }
                                        atype = new CArrayType(atype.ElementType, len);
                                    }
                                    else
                                    {
                                        //Report.Error();
                                    }
                                }
                                //var init = GetInitExpression(idecl.Initializer);
                                block.AddVariable(name, ctype ?? CBasicType.SignedInt);
                            }

                            if (idecl.Initializer != null)
                            {
                                var varExpr  = new VariableExpression(name, Location.Null, Location.Null);
                                var initExpr = GetInitializerExpression(idecl.Initializer);
                                block.InitStatements.Add(new ExpressionStatement(new AssignExpression(varExpr, initExpr)));
                            }
                        }
                    }
                }
        Executable CompileExecutable()
        {
            var exe        = new Executable(options.MachineInfo);
            var exeContext = new ExecutableContext(exe, options.Report);

            // Put something at the zero address so we don't get 0 addresses of globals
            exe.AddGlobal("__zero__", CBasicType.SignedInt);

            //
            // Find Variables, Functions, Types
            //
            var exeInitBody = new Block(VariableScope.Local);
            var tucs        = tus.Select(x => new TranslationUnitContext(x, exeContext));
            var tuInits     = new List <(CompiledFunction, EmitContext)> ();

            foreach (var tuc in tucs)
            {
                var tu = tuc.TranslationUnit;
                AddStatementDeclarations(tuc);
                if (tu.InitStatements.Count > 0)
                {
                    var tuInitBody = new Block(VariableScope.Local);
                    tuInitBody.AddStatements(tu.InitStatements);
                    var tuInit = new CompiledFunction($"__{tu.Name}__cinit", CFunctionType.VoidProcedure, tuInitBody);
                    exeInitBody.AddStatement(new ExpressionStatement(new FuncallExpression(new VariableExpression(tuInit.Name, Location.Null, Location.Null))));
                    tuInits.Add((tuInit, tuc));
                    exe.Functions.Add(tuInit);
                }
            }

            //
            // Generate a function to init globals
            //
            var exeInit = new CompiledFunction($"__cinit", CFunctionType.VoidProcedure, exeInitBody);

            exe.Functions.Add(exeInit);

            //
            // Link everything together
            // This is done before compilation to make sure everything is visible (for recursion)
            //
            var functionsToCompile = new List <(CompiledFunction, EmitContext)> {
                (exeInit, exeContext)
            };

            functionsToCompile.AddRange(tuInits);
            foreach (var tuc in tucs)
            {
                var tu = tuc.TranslationUnit;
                foreach (var g in tu.Variables)
                {
                    var v = exe.AddGlobal(g.Name, g.VariableType);
                    v.InitialValue = g.InitialValue;
                }
                var funcs = tu.Functions.Where(x => x.Body != null).ToList();
                exe.Functions.AddRange(funcs);
                functionsToCompile.AddRange(funcs.Select(x => (x, (EmitContext)tuc)));
            }

            //
            // Compile functions
            //
            foreach (var(f, pc) in functionsToCompile)
            {
                var body = f.Body;
                if (body == null)
                {
                    continue;
                }
                var fc = new FunctionContext(exe, f, pc);
                AddStatementDeclarations(fc);
                body.Emit(fc);
                f.LocalVariables.AddRange(fc.LocalVariables);

                // Make sure it returns
                if (body.Statements.Count == 0 || !body.AlwaysReturns)
                {
                    if (f.FunctionType.ReturnType.IsVoid)
                    {
                        fc.Emit(OpCode.Return);
                    }
                    else
                    {
                        options.Report.Error(161, "'" + f.Name + "' not all code paths return a value");
                    }
                }
            }

            return(exe);
        }

        void AddStatementDeclarations(BlockContext context)
        {
            var block = context.Block;

            foreach (var s in block.Statements)
            {
                s.AddDeclarationToBlock(context);
            }
        }

        FunctionDeclarator?GetFunctionDeclarator(Declarator?d)
        {
            if (d == null)
            {
                return(null);
            }
            else if (d is FunctionDeclarator)
            {
                return((FunctionDeclarator)d);
            }
            else
            {
                return(GetFunctionDeclarator(d.InnerDeclarator));
            }
        }
    }