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)); } } }
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))); } } } }