Auto stack size calculation
This commit is contained in:
parent
11ccd45663
commit
906759a515
6
Makefile
Normal file
6
Makefile
Normal file
@ -0,0 +1,6 @@
|
||||
|
||||
test-all:
|
||||
python ifcc-test.py testfiles
|
||||
|
||||
test-last:
|
||||
python ifcc-test.py -v -v testfiles/$(shell ls -A testfiles | tail -n 1)
|
||||
6
compiler/.clangd
Normal file
6
compiler/.clangd
Normal file
@ -0,0 +1,6 @@
|
||||
CompileFlags:
|
||||
Add:
|
||||
- "-I/opt/homebrew/opt/antlr4-cpp-runtime/include/antlr4-runtime"
|
||||
- "-I./generated"
|
||||
- "-std=c++17"
|
||||
|
||||
@ -1,32 +1,43 @@
|
||||
#include "CodeGenVisitor.h"
|
||||
|
||||
#include "generated/ifccParser.h"
|
||||
|
||||
antlrcpp::Any CodeGenVisitor::visitStmt(ifccParser::StmtContext *ctx) {
|
||||
std::any CodeGenVisitor::visitProg(ifccParser::ProgContext *ctx) {
|
||||
scopeStack.push_back("main");
|
||||
int size = symbolTable->stackSize(currentScope());
|
||||
#ifdef __APPLE__
|
||||
std::cout << ".globl _main\n_main:\n";
|
||||
std::cout << " sub sp, sp, #" << size << "\n";
|
||||
#else
|
||||
std::cout << ".globl main\nmain:\n";
|
||||
std::cout << " subq $" << size << ", %rsp\n";
|
||||
#endif
|
||||
|
||||
this->visitChildren(ctx);
|
||||
|
||||
#ifdef __APPLE__
|
||||
std::cout << " add sp, sp, #" << size << "\n";
|
||||
#else
|
||||
std::cout << " addq $" << size << ", %rsp\n";
|
||||
#endif
|
||||
std::cout << " ret\n";
|
||||
scopeStack.pop_back();
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::any CodeGenVisitor::visitStmt(ifccParser::StmtContext *ctx) {
|
||||
std::cout << " ;" << ctx->getText() << "\n";
|
||||
return this->visitChildren(ctx);
|
||||
}
|
||||
|
||||
// Declare a new variable: reserve a slot on the stack, mark as uninitialized.
|
||||
antlrcpp::Any CodeGenVisitor::visitDecl_stmt(ifccParser::Decl_stmtContext *ctx) {
|
||||
std::string name = ctx->VAR_NAME()->getText();
|
||||
if (symbolTable.find(name) != symbolTable.end()) {
|
||||
std::cerr << "error: variable '" << name << "' already declared\n";
|
||||
return 1;
|
||||
}
|
||||
symbolTable[name] = {nextOffset, false};
|
||||
nextOffset += 4;
|
||||
// Declaration pass already filled the symbol table: nothing to do here.
|
||||
std::any CodeGenVisitor::visitDecl_stmt(ifccParser::Decl_stmtContext *ctx) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Assign a value to a variable: evaluate val, store on stack, mark as initialized.
|
||||
antlrcpp::Any CodeGenVisitor::visitSet_stmt(ifccParser::Set_stmtContext *ctx) {
|
||||
std::any CodeGenVisitor::visitSet_stmt(ifccParser::Set_stmtContext *ctx) {
|
||||
std::string name = ctx->VAR_NAME()->getText();
|
||||
if (symbolTable.find(name) == symbolTable.end()) {
|
||||
std::cerr << "error: variable '" << name << "' undeclared\n";
|
||||
return 1;
|
||||
}
|
||||
int offset = symbolTable[name].offset;
|
||||
int offset = symbolTable->getOffset(currentScope(), name);
|
||||
|
||||
this->visit(ctx->val());
|
||||
|
||||
@ -36,12 +47,12 @@ antlrcpp::Any CodeGenVisitor::visitSet_stmt(ifccParser::Set_stmtContext *ctx) {
|
||||
std::cout << " movl %eax, " << offset << "(%rsp)\n";
|
||||
#endif
|
||||
|
||||
symbolTable[name].initialized = true;
|
||||
symbolTable->markInitialized(currentScope(), name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Load a constant or variable into the accumulator register
|
||||
antlrcpp::Any CodeGenVisitor::visitVal(ifccParser::ValContext *ctx) {
|
||||
// Load a constant or variable into the accumulator register.
|
||||
std::any CodeGenVisitor::visitVal(ifccParser::ValContext *ctx) {
|
||||
if (ctx->CONST()) {
|
||||
int val = stoi(ctx->CONST()->getText());
|
||||
#ifdef __APPLE__
|
||||
@ -51,50 +62,21 @@ antlrcpp::Any CodeGenVisitor::visitVal(ifccParser::ValContext *ctx) {
|
||||
#endif
|
||||
return val;
|
||||
}
|
||||
|
||||
std::string name = ctx->VAR_NAME()->getText();
|
||||
if (symbolTable.find(name) == symbolTable.end()) {
|
||||
std::cerr << "error: variable '" << name << "' undeclared\n";
|
||||
return 1;
|
||||
}
|
||||
if (!symbolTable[name].initialized) {
|
||||
std::cerr << "warning: variable '" << name << "' used before initialization\n";
|
||||
}
|
||||
int offset = symbolTable[name].offset;
|
||||
int offset = symbolTable->getOffset(currentScope(), name);
|
||||
symbolTable->isInitialized(currentScope(), name); // emits warning if needed
|
||||
|
||||
#ifdef __APPLE__
|
||||
std::cout << " ldr w0, [sp, #" << offset << "]\n";
|
||||
#else
|
||||
std::cout << " movl " << offset << "(%rsp), %eax\n";
|
||||
#endif
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
antlrcpp::Any CodeGenVisitor::visitProg(ifccParser::ProgContext *ctx) {
|
||||
#ifdef __APPLE__
|
||||
std::cout << ".globl _main\n";
|
||||
std::cout << "_main:\n";
|
||||
// Prologue: reserve space for local variables
|
||||
std::cout << " sub sp, sp, #16\n";
|
||||
#else
|
||||
std::cout << ".globl main\n";
|
||||
std::cout << "main:\n";
|
||||
// Prologue: reserve space for local variables
|
||||
std::cout << " subq $16, %rsp\n";
|
||||
#endif
|
||||
|
||||
this->visitChildren(ctx);
|
||||
|
||||
// Epilogue
|
||||
#ifdef __APPLE__
|
||||
std::cout << " add sp, sp, #16\n";
|
||||
#else
|
||||
std::cout << " addq $16, %rsp\n";
|
||||
#endif
|
||||
std::cout << " ret\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
antlrcpp::Any CodeGenVisitor::visitReturn_stmt(ifccParser::Return_stmtContext *ctx) {
|
||||
// Evaluate the return value into the accumulator register
|
||||
std::any CodeGenVisitor::visitReturn_stmt(ifccParser::Return_stmtContext *ctx) {
|
||||
this->visit(ctx->val());
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1,31 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "antlr4-runtime.h"
|
||||
#include "SymbolTable.h"
|
||||
#include "generated/ifccBaseVisitor.h"
|
||||
|
||||
|
||||
class CodeGenVisitor : public ifccBaseVisitor {
|
||||
SymbolTable *symbolTable; // shared, not owned
|
||||
std::vector<std::string> scopeStack; // navigation state, owned by this visitor
|
||||
|
||||
struct VarInfo {
|
||||
int offset; // stack offset relative to sp
|
||||
bool initialized; // true after a set_stmt assigns a value
|
||||
};
|
||||
|
||||
// Symbol table: variable name -> VarInfo
|
||||
std::map<std::string, VarInfo> symbolTable;
|
||||
int nextOffset = 0; // first variable at [sp, #0], next at [sp, #4], etc.
|
||||
std::string currentScope() const { return scopeStack.back(); }
|
||||
|
||||
public:
|
||||
explicit CodeGenVisitor(SymbolTable *st) : symbolTable(st) {
|
||||
}
|
||||
|
||||
std::any visitProg(ifccParser::ProgContext *ctx) override;
|
||||
|
||||
std::any visitStmt(ifccParser::StmtContext *ctx) override;
|
||||
|
||||
std::any visitReturn_stmt(ifccParser::Return_stmtContext *ctx) override;
|
||||
|
||||
std::any visitDecl_stmt(ifccParser::Decl_stmtContext *ctx) override;
|
||||
|
||||
std::any visitSet_stmt(ifccParser::Set_stmtContext *ctx) override;
|
||||
|
||||
std::any visitVal(ifccParser::ValContext *ctx) override;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
36
compiler/DeclarationVisitor.cpp
Normal file
36
compiler/DeclarationVisitor.cpp
Normal file
@ -0,0 +1,36 @@
|
||||
#include "DeclarationVisitor.h"
|
||||
|
||||
#include "generated/ifccParser.h"
|
||||
|
||||
std::any DeclarationVisitor::visitProg(ifccParser::ProgContext *ctx) {
|
||||
symbolTable->addScope("main");
|
||||
scopeStack.push_back("main");
|
||||
this->visitChildren(ctx);
|
||||
scopeStack.pop_back();
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::any DeclarationVisitor::visitStmt(ifccParser::StmtContext *ctx) {
|
||||
return this->visitChildren(ctx);
|
||||
}
|
||||
|
||||
std::any DeclarationVisitor::visitDecl_stmt(ifccParser::Decl_stmtContext *ctx) {
|
||||
std::vector<antlr4::tree::TerminalNode*> vars = ctx->VAR_NAME();
|
||||
for (auto var : vars) {
|
||||
std::string name = var->getText();
|
||||
symbolTable->declare(currentScope(), name);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::any DeclarationVisitor::visitSet_stmt(ifccParser::Set_stmtContext *ctx) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::any DeclarationVisitor::visitVal(ifccParser::ValContext *ctx) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::any DeclarationVisitor::visitReturn_stmt(ifccParser::Return_stmtContext *ctx) {
|
||||
return 0;
|
||||
}
|
||||
39
compiler/DeclarationVisitor.h
Normal file
39
compiler/DeclarationVisitor.h
Normal file
@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "antlr4-runtime.h"
|
||||
#include "SymbolTable.h"
|
||||
#include "generated/ifccBaseVisitor.h"
|
||||
|
||||
|
||||
class DeclarationVisitor : public ifccBaseVisitor {
|
||||
SymbolTable *symbolTable = new SymbolTable();
|
||||
|
||||
std::vector<std::string> scopeStack;
|
||||
|
||||
const std::string ¤tScope() const { return scopeStack.back(); }
|
||||
|
||||
public:
|
||||
~DeclarationVisitor() override {
|
||||
delete symbolTable;
|
||||
}
|
||||
|
||||
[[nodiscard]] SymbolTable *getSymbolTable() const {
|
||||
return symbolTable;
|
||||
}
|
||||
|
||||
std::any visitProg(ifccParser::ProgContext *ctx) override;
|
||||
|
||||
std::any visitStmt(ifccParser::StmtContext *ctx) override;
|
||||
|
||||
std::any visitReturn_stmt(ifccParser::Return_stmtContext *ctx) override;
|
||||
|
||||
std::any visitDecl_stmt(ifccParser::Decl_stmtContext *ctx) override;
|
||||
|
||||
std::any visitSet_stmt(ifccParser::Set_stmtContext *ctx) override;
|
||||
|
||||
std::any visitVal(ifccParser::ValContext *ctx) override;
|
||||
};
|
||||
|
||||
|
||||
@ -18,7 +18,9 @@ OBJECTS=build/ifccBaseVisitor.o \
|
||||
build/ifccVisitor.o \
|
||||
build/ifccParser.o \
|
||||
build/main.o \
|
||||
build/CodeGenVisitor.o
|
||||
build/CodeGenVisitor.o \
|
||||
build/DeclarationVisitor.o \
|
||||
build/SymbolTable.o
|
||||
|
||||
ifcc: $(OBJECTS)
|
||||
@mkdir -p build
|
||||
|
||||
1
compiler/SymbolTable.cpp
Normal file
1
compiler/SymbolTable.cpp
Normal file
@ -0,0 +1 @@
|
||||
#include "SymbolTable.h"
|
||||
97
compiler/SymbolTable.h
Normal file
97
compiler/SymbolTable.h
Normal file
@ -0,0 +1,97 @@
|
||||
#pragma once
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
class SymbolTable {
|
||||
struct VarInfo {
|
||||
int offset;
|
||||
bool initialized;
|
||||
};
|
||||
|
||||
struct Scope {
|
||||
std::string functionName;
|
||||
std::map<std::string, VarInfo> vars;
|
||||
int nextOffset = 0;
|
||||
};
|
||||
|
||||
std::map<std::string, Scope> scopes; // name -> Scope
|
||||
|
||||
public:
|
||||
// Creates a new scope (call in DeclarationVisitor).
|
||||
void addScope(const std::string &functionName) {
|
||||
if (scopes.count(functionName)) {
|
||||
std::cerr << "error: scope '" << functionName << "' already exists\n";
|
||||
exit(1);
|
||||
}
|
||||
scopes[functionName] = {functionName, {}, 0};
|
||||
}
|
||||
|
||||
// Declare a variable in a named scope; returns its stack offset.
|
||||
int declare(const std::string &scopeName, const std::string &name) {
|
||||
auto &scope = getScope(scopeName);
|
||||
if (scope.vars.count(name)) {
|
||||
std::cerr << "error: variable '" << name << "' already declared in '" << scopeName << "'\n";
|
||||
exit(1);
|
||||
}
|
||||
int offset = scope.nextOffset;
|
||||
scope.vars[name] = {offset, false};
|
||||
scope.nextOffset += 4;
|
||||
return offset;
|
||||
}
|
||||
|
||||
int getOffset(const std::string &scopeName, const std::string &name) {
|
||||
auto &vars = getScope(scopeName).vars;
|
||||
if (!vars.count(name)) {
|
||||
std::cerr << "error: variable '" << name << "' undeclared in '" << scopeName << "'\n";
|
||||
exit(1);
|
||||
}
|
||||
return vars[name].offset;
|
||||
}
|
||||
|
||||
bool isDeclared(const std::string &scopeName, const std::string &name) const {
|
||||
if (!scopes.count(scopeName)) return false;
|
||||
return scopes.at(scopeName).vars.count(name) > 0;
|
||||
}
|
||||
|
||||
void markInitialized(const std::string &scopeName, const std::string &name) {
|
||||
auto &vars = getScope(scopeName).vars;
|
||||
if (!vars.count(name)) {
|
||||
std::cerr << "error: variable '" << name << "' undeclared in '" << scopeName << "'\n";
|
||||
exit(1);
|
||||
}
|
||||
vars[name].initialized = true;
|
||||
}
|
||||
|
||||
bool isInitialized(const std::string &scopeName, const std::string &name) {
|
||||
if (!isDeclared(scopeName, name)) return false;
|
||||
if (!scopes.at(scopeName).vars[name].initialized) {
|
||||
std::cerr << "warning: variable '" << name << "' used before initialization\n";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Stack size for a given scope, aligned to 16 bytes.
|
||||
int stackSize(const std::string &scopeName) const {
|
||||
int n = getScope(scopeName).nextOffset;
|
||||
return (n + 15) & ~15;
|
||||
}
|
||||
|
||||
private:
|
||||
Scope &getScope(const std::string &name) {
|
||||
if (!scopes.count(name)) {
|
||||
std::cerr << "error: scope '" << name << "' not found\n";
|
||||
exit(1);
|
||||
}
|
||||
return scopes.at(name);
|
||||
}
|
||||
|
||||
const Scope &getScope(const std::string &name) const {
|
||||
if (!scopes.count(name)) {
|
||||
std::cerr << "error: scope '" << name << "' not found\n";
|
||||
exit(1);
|
||||
}
|
||||
return scopes.at(name);
|
||||
}
|
||||
};
|
||||
@ -8,7 +8,7 @@ stmt: decl_stmt | set_stmt | return_stmt ;
|
||||
|
||||
return_stmt: RETURN val ';' ;
|
||||
|
||||
decl_stmt: 'int' VAR_NAME ';' ;
|
||||
decl_stmt: 'int' (VAR_NAME ',')* VAR_NAME ';' ;
|
||||
set_stmt: VAR_NAME '=' val ';' ;
|
||||
|
||||
val: CONST | VAR_NAME ;
|
||||
|
||||
@ -9,25 +9,21 @@
|
||||
#include "generated/ifccBaseVisitor.h"
|
||||
|
||||
#include "CodeGenVisitor.h"
|
||||
#include "DeclarationVisitor.h"
|
||||
|
||||
using namespace antlr4;
|
||||
using namespace std;
|
||||
|
||||
int main(int argn, const char **argv)
|
||||
{
|
||||
int main(int argn, const char **argv) {
|
||||
stringstream in;
|
||||
if (argn==2)
|
||||
{
|
||||
if (argn == 2) {
|
||||
ifstream lecture(argv[1]);
|
||||
if( !lecture.good() )
|
||||
{
|
||||
if (!lecture.good()) {
|
||||
cerr << "error: cannot read file: " << argv[1] << endl;
|
||||
exit(1);
|
||||
}
|
||||
in << lecture.rdbuf();
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
cerr << "usage: ifcc path/to/file.c" << endl;
|
||||
exit(1);
|
||||
}
|
||||
@ -42,15 +38,16 @@ int main(int argn, const char **argv)
|
||||
ifccParser parser(&tokens);
|
||||
tree::ParseTree *tree = parser.axiom();
|
||||
|
||||
if(parser.getNumberOfSyntaxErrors() != 0)
|
||||
{
|
||||
if (parser.getNumberOfSyntaxErrors() != 0) {
|
||||
cerr << "error: syntax error during parsing" << endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
DeclarationVisitor dv;
|
||||
dv.visit(tree);
|
||||
|
||||
CodeGenVisitor v;
|
||||
v.visit(tree);
|
||||
CodeGenVisitor cgv = CodeGenVisitor(dv.getSymbolTable());
|
||||
cgv.visit(tree);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
24
ifcc-test.py
24
ifcc-test.py
@ -67,7 +67,7 @@ epilog="examples:\n\n"
|
||||
+twf("python3 ifcc-test.py path/to/some/dir/*.c path/to/some/other/dir")+'\n'
|
||||
+'\n'
|
||||
+twf("python3 ifcc-test.py -o ./myprog path/to/some/source.c")+'\n'
|
||||
+twf("python3 ifcc-test.py -S -o truc.s truc.c")+'\n'
|
||||
+twf("python3 ifcc-test.py -S -o truc.asm truc.c")+'\n'
|
||||
,
|
||||
)
|
||||
|
||||
@ -137,8 +137,8 @@ if args.S or args.c or args.output:
|
||||
exit(1)
|
||||
|
||||
if args.S: # produce assembly
|
||||
if args.output[-2:] != ".s":
|
||||
print("error: output file name must end with '.s'")
|
||||
if args.output[-2:] != ".asm":
|
||||
print("error: output file name must end with '.asm'")
|
||||
exit(1)
|
||||
ifccstatus=run_command(f'{pld_base_dir}/compiler/ifcc {inputfilename} > {args.output}')
|
||||
if ifccstatus: # let's show error messages on screen
|
||||
@ -150,17 +150,17 @@ if args.S or args.c or args.output:
|
||||
if args.output[-2:] != ".o":
|
||||
print("error: output file name must end with '.o'")
|
||||
exit(1)
|
||||
asmname=args.output[:-2]+".s"
|
||||
asmname=args.output[:-2]+".asm"
|
||||
ifccstatus=run_command(f'{pld_base_dir}/compiler/ifcc {inputfilename} > {asmname}')
|
||||
if ifccstatus: # let's show error messages on screen
|
||||
exit(run_command(f'{pld_base_dir}/compiler/ifcc {inputfilename}',toscreen=True))
|
||||
exit(run_command(f'gcc -c -o {args.output} {asmname}',toscreen=True))
|
||||
|
||||
else: # produce an executable
|
||||
if args.output[-2:] in [".o",".c",".s"]:
|
||||
if args.output[-2:] in [".o",".c",".asm"]:
|
||||
print("error: incorrect name for an executable: "+args.output)
|
||||
exit(1)
|
||||
asmname=args.output+".s"
|
||||
asmname=args.output+".asm"
|
||||
ifccstatus=run_command(f'{pld_base_dir}/compiler/ifcc {inputfilename} > {asmname}')
|
||||
if ifccstatus:
|
||||
exit(run_command(f'{pld_base_dir}/compiler/ifcc {inputfilename}', toscreen=True))
|
||||
@ -271,17 +271,17 @@ for jobname in jobs:
|
||||
os.chdir(jobname)
|
||||
|
||||
## Reference compiler = GCC
|
||||
gccstatus=run_command("gcc -S -o asm-gcc.s input.c", "gcc-compile.txt")
|
||||
gccstatus=run_command("gcc -S -o asm-gcc.asm input.c", "gcc-compile.txt")
|
||||
if gccstatus == 0:
|
||||
# test-case is a valid program. we should run it
|
||||
gccstatus=run_command("gcc -o exe-gcc asm-gcc.s", "gcc-link.txt")
|
||||
gccstatus=run_command("gcc -o exe-gcc asm-gcc.asm", "gcc-link.txt")
|
||||
if gccstatus == 0: # then both compile and link stage went well
|
||||
exegccstatus=run_command("./exe-gcc", "gcc-execute.txt")
|
||||
if args.verbose >=2:
|
||||
dumpfile("gcc-execute.txt")
|
||||
|
||||
## IFCC compiler
|
||||
ifccstatus=run_command(f'{pld_base_dir}/compiler/ifcc input.c > asm-ifcc.s', 'ifcc-compile.txt')
|
||||
ifccstatus=run_command(f'{pld_base_dir}/compiler/ifcc input.c > asm-ifcc.asm', 'ifcc-compile.txt')
|
||||
|
||||
if gccstatus != 0 and ifccstatus != 0:
|
||||
## ifcc correctly rejects invalid program -> test-case ok
|
||||
@ -297,17 +297,17 @@ for jobname in jobs:
|
||||
print("TEST FAIL (your compiler rejects a valid program)")
|
||||
all_ok=False
|
||||
if args.verbose:
|
||||
dumpfile("asm-ifcc.s") # stdout of ifcc
|
||||
dumpfile("asm-ifcc.asm") # stdout of ifcc
|
||||
dumpfile("ifcc-compile.txt") # stderr of ifcc
|
||||
continue
|
||||
else:
|
||||
## ifcc accepts to compile valid program -> let's link it
|
||||
ldstatus=run_command("gcc -o exe-ifcc asm-ifcc.s", "ifcc-link.txt")
|
||||
ldstatus=run_command("gcc -o exe-ifcc asm-ifcc.asm", "ifcc-link.txt")
|
||||
if ldstatus:
|
||||
print("TEST FAIL (your compiler produces incorrect assembly)")
|
||||
all_ok=False
|
||||
if args.verbose:
|
||||
dumpfile("asm-ifcc.s")
|
||||
dumpfile("asm-ifcc.asm")
|
||||
dumpfile("ifcc-link.txt")
|
||||
continue
|
||||
|
||||
|
||||
@ -1,11 +0,0 @@
|
||||
gcc: gcca main-gcc.asm
|
||||
gcc -o main-gcc.o main-gcc.asm
|
||||
gcca: main.c
|
||||
gcc -S -o main-gcc.asm main.c
|
||||
|
||||
ifcc: ifcca main-ifcc.asm
|
||||
gcc -o main-ifcc.o main-ifcc.asm
|
||||
ifcca: main.c comp-ifcc
|
||||
../compiler/ifcc main.c > main-ifcc.asm
|
||||
comp-ifcc:
|
||||
cd ../compiler && make
|
||||
10
prog/main.c
10
prog/main.c
@ -1,10 +0,0 @@
|
||||
int main() {
|
||||
int z;
|
||||
int x;
|
||||
x = 56;
|
||||
int y;
|
||||
x = y;
|
||||
y = 10;
|
||||
z = x;
|
||||
return z;
|
||||
}
|
||||
@ -1,8 +1,8 @@
|
||||
int main() {
|
||||
int z;
|
||||
int x;
|
||||
int z, x;
|
||||
x = 56;
|
||||
int y;
|
||||
int n, o;
|
||||
y = 10;
|
||||
x = y;
|
||||
z = x;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user