Refactor to generalise assembler output
This commit is contained in:
parent
39756f4e89
commit
216d6c6b5e
|
@ -8,7 +8,9 @@ include_directories(include)
|
|||
add_executable(Erythro
|
||||
include/Data.h
|
||||
include/Defs.h
|
||||
src/Assembler.c
|
||||
src/assemble/AssemblerDispatcher.c
|
||||
src/assemble/ASMAssembler.c
|
||||
src/assemble/QBEAssembler.c
|
||||
src/Delegate.c
|
||||
src/Dump.c
|
||||
src/Lexer.c
|
||||
|
@ -18,4 +20,5 @@ add_executable(Erythro
|
|||
src/Statements.c
|
||||
src/Symbols.c
|
||||
src/Types.c
|
||||
src/Importer.c)
|
||||
src/Importer.c
|
||||
src/assemble/JVMAssembler.c)
|
||||
|
|
|
@ -48,6 +48,10 @@ extern_ bool OptVerboseOutput;
|
|||
extern_ char* OutputFileName;
|
||||
// The sizes of each of the core types, in bytes.
|
||||
extern_ int TypeSizes[5];
|
||||
// The name of the Assembler Module that we should use.
|
||||
extern_ char* OptAssemblerName;
|
||||
// The Assembler Module to call to when performing generation operations.
|
||||
extern_ struct AssemblerModule* Assembler;
|
||||
|
||||
// The names of each token in the language, synchronized to the TokenTypes enum.
|
||||
extern_ char* TokenNames[];
|
||||
|
|
175
include/Defs.h
175
include/Defs.h
|
@ -513,113 +513,96 @@ void DieBinary(char* Error, int Number);
|
|||
* * * * C O D E G E N E R A T I O N * * * *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
int AssembleTree(struct ASTNode* Node, int Register, int LoopBeginLabel, int LoopEndLabel, int ParentOp);
|
||||
int PrimitiveSize (int);
|
||||
|
||||
void DeallocateAllRegisters();
|
||||
/**
|
||||
* All of the functions required to be implemented by an Assembler Module.
|
||||
*/
|
||||
struct AssemblerVtable {
|
||||
// Entry Point
|
||||
int (*AssembleTree)(struct ASTNode*, int, int, int, int);
|
||||
// Register management
|
||||
void (*DeallocateAllRegisters)();
|
||||
int (*RetrieveRegister)();
|
||||
void (*DeallocateRegister)(int);
|
||||
// Alignment
|
||||
int (*AsAlignMemory)(int, int, int);
|
||||
int (*AsCalcOffset)(int);
|
||||
void (*AsNewStackFrame)();
|
||||
// Basic operations
|
||||
int (*AsLoad)(int);
|
||||
int (*AsAdd)(int, int);
|
||||
int (*AsMul)(int, int);
|
||||
int (*AsSub)(int, int);
|
||||
int (*AsDiv)(int, int);
|
||||
int (*AsLdGlobalVar)(struct SymbolTableEntry*, int);
|
||||
int (*AsLdLocalVar)(struct SymbolTableEntry*, int);
|
||||
int (*AsStrGlobalVar)(struct SymbolTableEntry*, int);
|
||||
int (*AsStrLocalVar)(struct SymbolTableEntry*, int);
|
||||
int (*AsDeref)(int, int);
|
||||
int (*AsStrDeref)(int, int, int);
|
||||
int (*AsAddr)(struct SymbolTableEntry*);
|
||||
int (*AsNewString)(char*);
|
||||
int (*AsLoadString)(int);
|
||||
|
||||
int RetrieveRegister();
|
||||
// Comparisons
|
||||
int (*AsEqual)(int, int);
|
||||
int (*AsIneq)(int, int);
|
||||
int (*AsLess)(int, int);
|
||||
int (*AsGreat)(int, int);
|
||||
int (*AsLessE)(int, int);
|
||||
int (*AsGreatE)(int, int);
|
||||
|
||||
void DeallocateRegister(int Register);
|
||||
// Binary operations
|
||||
int (*AsBitwiseAND)(int, int);
|
||||
int (*AsBitwiseOR)(int, int);
|
||||
int (*AsBitwiseXOR)(int, int);
|
||||
int (*AsNegate)(int);
|
||||
int (*AsInvert)(int);
|
||||
int (*AsBooleanNOT)(int);
|
||||
int (*AsShiftLeft)(int, int);
|
||||
int (*AsShiftRight)(int, int);
|
||||
|
||||
int PrimitiveSize(int Type);
|
||||
// Comparisons
|
||||
int (*AsBooleanConvert)(int, int, int);
|
||||
int (*AsCompareJmp)(int, int, int, int);
|
||||
int (*AsCompare)(int, int, int);
|
||||
|
||||
int AsAlignMemory(int Type, int Offset, int Direction);
|
||||
// Loops and jumps
|
||||
int (*AsIf)(struct ASTNode*, int, int);
|
||||
int (*AsWhile)(struct ASTNode*);
|
||||
int (*NewLabel)();
|
||||
void (*AsJmp)(int);
|
||||
void (*AsLabel)(int);
|
||||
|
||||
int AsLoad(int Value);
|
||||
// Call and return
|
||||
int (*AsShl)(int, int);
|
||||
int (*AsReturn)(struct SymbolTableEntry*, int);
|
||||
int (*AsCallWrapper)(struct ASTNode*);
|
||||
void (*AsCopyArgs)(int, int);
|
||||
int (*AsCall)(struct SymbolTableEntry*, int);
|
||||
void (*AssemblerPrint)(int);
|
||||
|
||||
int AsAdd(int Left, int Right);
|
||||
// Preamble and epilogue
|
||||
void (*AsGlobalSymbol)(struct SymbolTableEntry*);
|
||||
void (*AssemblerPreamble)();
|
||||
void (*AsFunctionPreamble)(struct SymbolTableEntry*);
|
||||
void (*AsFunctionEpilogue)(struct SymbolTableEntry*);
|
||||
};
|
||||
|
||||
int AsMul(int Left, int Right);
|
||||
struct AssemblerModule{
|
||||
char* name;
|
||||
const struct AssemblerVtable* vtable;
|
||||
};
|
||||
|
||||
int AsSub(int Left, int Right);
|
||||
int RegisterModule(struct AssemblerModule*);
|
||||
|
||||
int AsDiv(int Left, int Right);
|
||||
void RegisterAllModules();
|
||||
|
||||
int AsLdGlobalVar(struct SymbolTableEntry* Entry, int Operation);
|
||||
|
||||
int AsLdLocalVar(struct SymbolTableEntry* Entry, int Operation);
|
||||
|
||||
int AsStrGlobalVar(struct SymbolTableEntry* Entry, int Register);
|
||||
|
||||
int AsStrLocalVar(struct SymbolTableEntry* Entry, int Register);
|
||||
|
||||
int AsCalcOffset(int Type);
|
||||
|
||||
void AsNewStackFrame();
|
||||
|
||||
int AsDeref(int Reg, int Type);
|
||||
|
||||
int AsStrDeref(int Register1, int Register2, int Type);
|
||||
|
||||
int AsAddr(struct SymbolTableEntry* Entry);
|
||||
|
||||
void AsGlobalSymbol(struct SymbolTableEntry* Entry);
|
||||
|
||||
int AsNewString(char* Value);
|
||||
|
||||
int AsLoadString(int ID);
|
||||
|
||||
int AsEqual(int Left, int Right);
|
||||
|
||||
int AsIneq(int Left, int Right);
|
||||
|
||||
int AsLess(int Left, int Right);
|
||||
|
||||
int AsGreat(int Left, int Right);
|
||||
|
||||
int AsLessE(int Left, int Right);
|
||||
|
||||
int AsGreatE(int Left, int Right);
|
||||
|
||||
int AsBitwiseAND(int Left, int Right);
|
||||
|
||||
int AsBitwiseOR(int Left, int Right);
|
||||
|
||||
int AsBitwiseXOR(int Left, int Right);
|
||||
|
||||
int AsNegate(int Register);
|
||||
|
||||
int AsInvert(int Register);
|
||||
|
||||
int AsBooleanNOT(int Register);
|
||||
|
||||
int AsShiftLeft(int Left, int Right);
|
||||
|
||||
int AsShiftRight(int Left, int Right);
|
||||
|
||||
int AsBooleanConvert(int Register, int Operation, int Label);
|
||||
|
||||
int AsCompareJmp(int Operation, int RegisterLeft, int RegisterRight, int Label);
|
||||
|
||||
int AsCompare(int Operation, int RegisterLeft, int RegisterRight);
|
||||
|
||||
int AsIf(struct ASTNode* Node, int LoopStartLabel, int LoopEndLabel);
|
||||
|
||||
int NewLabel(void);
|
||||
|
||||
void AsJmp(int Label);
|
||||
|
||||
void AsLabel(int Label);
|
||||
|
||||
int AsShl(int Register, int Val);
|
||||
|
||||
int AsReturn(struct SymbolTableEntry* Entry, int Register);
|
||||
|
||||
int AsCallWrapper(struct ASTNode* Node);
|
||||
|
||||
void AsCopyArgs(int Register, int Position);
|
||||
|
||||
int AsCall(struct SymbolTableEntry* Entry, int Args);
|
||||
|
||||
int AsWhile(struct ASTNode* Node);
|
||||
|
||||
void AssemblerPrint(int Register);
|
||||
|
||||
void AssemblerPreamble();
|
||||
|
||||
void AsFunctionPreamble(struct SymbolTableEntry* Entry);
|
||||
|
||||
void AsFunctionEpilogue(struct SymbolTableEntry* Entry);
|
||||
// Module List
|
||||
void RegisterQBE();
|
||||
void RegisterWin32ASM();
|
||||
void RegisterJVM();
|
||||
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * *
|
||||
|
|
|
@ -95,7 +95,7 @@ void Compile(struct FileData* InputFile) {
|
|||
|
||||
Tokenise();
|
||||
|
||||
AssemblerPreamble();
|
||||
Assembler->vtable->AssemblerPreamble();
|
||||
|
||||
ParseGlobals();
|
||||
|
||||
|
|
12
src/Main.c
12
src/Main.c
|
@ -107,6 +107,7 @@ int main(int argc, char* argv[]) {
|
|||
OptAssembleFiles = true;
|
||||
OptLinkFiles = true;
|
||||
OptVerboseOutput = false;
|
||||
OptAssemblerName = "Win32 GAS ASM";
|
||||
|
||||
// Temporary .o storage and counter
|
||||
int ObjectCount = 0;
|
||||
|
@ -126,24 +127,32 @@ int main(int argc, char* argv[]) {
|
|||
switch (argv[i][j]) {
|
||||
case 'o': // output
|
||||
OutputFileName = argv[++i];
|
||||
|
||||
break;
|
||||
|
||||
case 'T': // print Tree (debug)
|
||||
OptDumpTree = true;
|
||||
break;
|
||||
|
||||
case 'c': // Compile only
|
||||
OptAssembleFiles = true;
|
||||
OptKeepAssembly = false;
|
||||
OptLinkFiles = false;
|
||||
break;
|
||||
|
||||
case 'S': // aSsemble only
|
||||
OptAssembleFiles = true;
|
||||
OptKeepAssembly = true;
|
||||
OptLinkFiles = false;
|
||||
break;
|
||||
|
||||
case 'v': // Verbose output
|
||||
OptVerboseOutput = true;
|
||||
break;
|
||||
|
||||
case 'm': // Specify Assembler Module
|
||||
OptAssemblerName = argv[++i];
|
||||
break;
|
||||
|
||||
default:
|
||||
DisplayUsage(argv[0]);
|
||||
}
|
||||
|
@ -159,6 +168,7 @@ int main(int argc, char* argv[]) {
|
|||
Files = malloc(sizeof(struct FileData*) * (argc - i) + 1);
|
||||
memset(Files, 0, sizeof(struct FileData*) * (argc - i) + 1);
|
||||
|
||||
RegisterAllModules();
|
||||
|
||||
// For the rest of the files specified, we can iterate them right to left.
|
||||
while (i < argc) {
|
||||
|
|
|
@ -241,7 +241,7 @@ struct ASTNode* ParsePrimary(void) {
|
|||
|
||||
case LI_STR:
|
||||
|
||||
ID = AsNewString(CurrentIdentifier);
|
||||
ID = Assembler->vtable->AsNewString(CurrentIdentifier);
|
||||
Node = ConstructASTLeaf(TERM_STRLITERAL, PointerTo(RET_CHAR), NULL, ID);
|
||||
break;
|
||||
|
||||
|
@ -621,7 +621,7 @@ void ParseGlobals() {
|
|||
Tree = ParseFunction(Type);
|
||||
if (Tree && CurrentFile->AllowDefinitions) {
|
||||
printf("\nBeginning assembler creation of new function %s\n", Tree->Symbol->Name);
|
||||
AssembleTree(Tree, -1, -1, -1, 0);
|
||||
Assembler->vtable->AssembleTree(Tree, -1, -1, -1, 0);
|
||||
FreeLocals();
|
||||
} else {
|
||||
printf("\nFunction prototype saved\r\n");
|
||||
|
|
|
@ -110,7 +110,7 @@ struct SymbolTableEntry* BeginCompositeDeclaration(int Type) {
|
|||
|
||||
for (Member = Member->NextSymbol; Member != NULL; Member = Member->NextSymbol) {
|
||||
if (Type == DAT_STRUCT)
|
||||
Member->SinkOffset = AsAlignMemory(Member->Type, Offset, 1);
|
||||
Member->SinkOffset = Assembler->vtable->AsAlignMemory(Member->Type, Offset, 1);
|
||||
else
|
||||
Member->SinkOffset = 0;
|
||||
|
||||
|
|
|
@ -257,7 +257,7 @@ struct SymbolTableEntry* AddSymbol(char* Name, int Type, int Structure, int Stor
|
|||
case SC_GLOBAL:
|
||||
AppendSymbol(&Globals, &GlobalsEnd, Node);
|
||||
// We don't want to generate a static block for functions.
|
||||
if (Structure != ST_FUNC) AsGlobalSymbol(Node);
|
||||
if (Structure != ST_FUNC) Assembler->vtable->AsGlobalSymbol(Node);
|
||||
break;
|
||||
case SC_STRUCT:
|
||||
AppendSymbol(&Structs, &StructsEnd, Node);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
39
src/assemble/AssemblerDispatcher.c
Normal file
39
src/assemble/AssemblerDispatcher.c
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*************/
|
||||
/*GEMWIRE */
|
||||
/* ERYTHRO*/
|
||||
/*************/
|
||||
|
||||
#include <Defs.h>
|
||||
#include <Data.h>
|
||||
|
||||
#define MODULES_SIZE 3
|
||||
struct AssemblerModule* modules[MODULES_SIZE];
|
||||
static int moduleID = 0;
|
||||
|
||||
void RegisterAllModules() {
|
||||
RegisterWin32ASM();
|
||||
RegisterQBE();
|
||||
RegisterJVM();
|
||||
|
||||
for (size_t i = 0; i < moduleID; i++) {
|
||||
if (strcmp(modules[i]->name, OptAssemblerName) == 0) {
|
||||
Assembler = modules[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Assembler == NULL) {
|
||||
DieMessage("Unable to find an Assembler for ", OptAssemblerName);
|
||||
} else {
|
||||
printf("Using %s assembler.\r\n", OptAssemblerName);
|
||||
}
|
||||
}
|
||||
|
||||
int RegisterModule(struct AssemblerModule* mod) {
|
||||
|
||||
printf("Registering Assembler Module for %s output.\r\n", mod->name);
|
||||
modules[moduleID] = mod;
|
||||
moduleID++;
|
||||
|
||||
return 0;
|
||||
}
|
180
src/assemble/JVMAssembler.c
Normal file
180
src/assemble/JVMAssembler.c
Normal file
|
@ -0,0 +1,180 @@
|
|||
|
||||
/*************/
|
||||
/*GEMWIRE */
|
||||
/* ERYTHRO*/
|
||||
/*************/
|
||||
|
||||
#include "Defs.h"
|
||||
#include "Data.h"
|
||||
|
||||
#define AGGREGATE(x) ":##x"
|
||||
#define GLOBAL(x) "$##x"
|
||||
#define TEMPORARY(x) "%##x"
|
||||
#define LABEL(x) "@##x"
|
||||
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* * * * R O O T O F A S S E M B L E R * * * *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
// Just a short "hack" to make sure we only dump the tree the first time this function is called
|
||||
static int Started = 0;
|
||||
|
||||
/*
|
||||
* Walk the AST tree given, and generate the assembly code that represents
|
||||
* it.
|
||||
*
|
||||
* @param Node: The current Node to compile. If needed, its children will be parsed recursively.
|
||||
* @param Register: The index of Registers to store the result of the current compilation.
|
||||
* @param ParentOp: The Operation of the parent of the current Node.
|
||||
*
|
||||
* @return dependant on the Node. Typically the Register that stores the result of the Node's operation.
|
||||
*
|
||||
*/
|
||||
static int AssembleTree(struct ASTNode* Node, int Register, int LoopBeginLabel, int LoopEndLabel, int ParentOp) {
|
||||
int LeftVal, RightVal;
|
||||
if (!Started && OptDumpTree)
|
||||
DumpTree(Node, 0);
|
||||
Started = 1;
|
||||
|
||||
printf("Current operation: %d\r\n", Node->Operation);
|
||||
switch (Node->Operation) {
|
||||
case OP_IF:
|
||||
|
||||
case OP_LOOP:
|
||||
|
||||
case OP_COMP:
|
||||
|
||||
case OP_CALL:
|
||||
|
||||
case OP_FUNC:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (Node->Left)
|
||||
LeftVal = AssembleTree(Node->Left, -1, LoopBeginLabel, LoopEndLabel, Node->Operation);
|
||||
|
||||
if (Node->Right)
|
||||
RightVal = AssembleTree(Node->Right, LeftVal, LoopBeginLabel, LoopEndLabel, Node->Operation);
|
||||
|
||||
switch (Node->Operation) {
|
||||
case OP_ADD:
|
||||
|
||||
case OP_SUBTRACT:
|
||||
|
||||
case OP_MULTIPLY:
|
||||
|
||||
case OP_DIVIDE:
|
||||
|
||||
case OP_SCALE:
|
||||
switch (Node->Size) {
|
||||
case 2:
|
||||
case 4:
|
||||
case 8:
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
case OP_BREAK:
|
||||
|
||||
case OP_CONTINUE:
|
||||
|
||||
case OP_ADDRESS:
|
||||
|
||||
case OP_DEREF:
|
||||
|
||||
case OP_ASSIGN:
|
||||
printf("Preparing for assignment..\r\n");
|
||||
if (Node->Right == NULL)
|
||||
Die("Fault in assigning a null rvalue");
|
||||
|
||||
printf("\tCalculating assignment for target %s:\r\n", Node->Right->Symbol->Name);
|
||||
switch (Node->Right->Operation) {
|
||||
case REF_IDENT:
|
||||
if (Node->Right->Symbol->Storage == SC_LOCAL) (void)0;
|
||||
|
||||
case OP_DEREF:
|
||||
default:
|
||||
DieDecimal("Can't ASSIGN in AssembleTree: ", Node->Operation);
|
||||
}; return 0;
|
||||
|
||||
case OP_WIDEN:
|
||||
|
||||
case OP_RET:
|
||||
|
||||
case OP_EQUAL:
|
||||
case OP_INEQ:
|
||||
case OP_LESS:
|
||||
case OP_GREAT:
|
||||
case OP_LESSE:
|
||||
case OP_GREATE:
|
||||
if (ParentOp == OP_IF || ParentOp == OP_LOOP) (void)0;
|
||||
|
||||
|
||||
case REF_IDENT:
|
||||
if (TypeIsPtr(Node->ExprType)) {
|
||||
}
|
||||
|
||||
if (Node->RVal || ParentOp == OP_DEREF) {
|
||||
if (Node->Symbol->Storage == SC_LOCAL || Node->Symbol->Storage == SC_PARAM) (void)0;
|
||||
} else
|
||||
return -1;
|
||||
|
||||
case TERM_INTLITERAL:
|
||||
|
||||
case TERM_STRLITERAL:
|
||||
|
||||
case OP_PRINT:
|
||||
|
||||
case OP_BITAND:
|
||||
|
||||
case OP_BITOR:
|
||||
|
||||
case OP_BITXOR:
|
||||
|
||||
case OP_SHIFTL:
|
||||
|
||||
case OP_SHIFTR:
|
||||
|
||||
case OP_POSTINC:
|
||||
if (Node->Symbol->Storage == SC_LOCAL || Node->Symbol->Storage == SC_PARAM) (void)0;
|
||||
|
||||
case OP_POSTDEC:
|
||||
if (Node->Symbol->Storage == SC_LOCAL || Node->Symbol->Storage == SC_PARAM) (void)0;
|
||||
|
||||
case OP_PREINC:
|
||||
if (Node->Symbol->Storage == SC_LOCAL || Node->Symbol->Storage == SC_PARAM) (void)0;
|
||||
|
||||
case OP_PREDEC:
|
||||
if (Node->Symbol->Storage == SC_LOCAL || Node->Symbol->Storage == SC_PARAM) (void)0;
|
||||
|
||||
case OP_BOOLNOT:
|
||||
|
||||
case OP_BITNOT:
|
||||
|
||||
case OP_NEGATE:
|
||||
|
||||
case OP_BOOLCONV:
|
||||
return 0;
|
||||
|
||||
default:
|
||||
DieDecimal("Unknown ASM Operation", Node->Operation);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct AssemblerVtable JVMAssemblerVtable = {
|
||||
.AssembleTree = AssembleTree
|
||||
};
|
||||
|
||||
static const struct AssemblerModule JVMAssemblerModule = {
|
||||
.name = "JVM Bytecode",
|
||||
.vtable = &JVMAssemblerVtable
|
||||
};
|
||||
|
||||
|
||||
void RegisterJVM() {
|
||||
RegisterModule(&JVMAssemblerModule);
|
||||
}
|
180
src/assemble/QBEAssembler.c
Normal file
180
src/assemble/QBEAssembler.c
Normal file
|
@ -0,0 +1,180 @@
|
|||
|
||||
/*************/
|
||||
/*GEMWIRE */
|
||||
/* ERYTHRO*/
|
||||
/*************/
|
||||
|
||||
#include "Defs.h"
|
||||
#include "Data.h"
|
||||
|
||||
#define AGGREGATE(x) ":##x"
|
||||
#define GLOBAL(x) "$##x"
|
||||
#define TEMPORARY(x) "%##x"
|
||||
#define LABEL(x) "@##x"
|
||||
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* * * * R O O T O F A S S E M B L E R * * * *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
// Just a short "hack" to make sure we only dump the tree the first time this function is called
|
||||
static int Started = 0;
|
||||
|
||||
/*
|
||||
* Walk the AST tree given, and generate the assembly code that represents
|
||||
* it.
|
||||
*
|
||||
* @param Node: The current Node to compile. If needed, its children will be parsed recursively.
|
||||
* @param Register: The index of Registers to store the result of the current compilation.
|
||||
* @param ParentOp: The Operation of the parent of the current Node.
|
||||
*
|
||||
* @return dependant on the Node. Typically the Register that stores the result of the Node's operation.
|
||||
*
|
||||
*/
|
||||
static int AssembleTree(struct ASTNode* Node, int Register, int LoopBeginLabel, int LoopEndLabel, int ParentOp) {
|
||||
int LeftVal, RightVal;
|
||||
if (!Started && OptDumpTree)
|
||||
DumpTree(Node, 0);
|
||||
Started = 1;
|
||||
|
||||
printf("Current operation: %d\r\n", Node->Operation);
|
||||
switch (Node->Operation) {
|
||||
case OP_IF:
|
||||
|
||||
case OP_LOOP:
|
||||
|
||||
case OP_COMP:
|
||||
|
||||
case OP_CALL:
|
||||
|
||||
case OP_FUNC:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (Node->Left)
|
||||
LeftVal = AssembleTree(Node->Left, -1, LoopBeginLabel, LoopEndLabel, Node->Operation);
|
||||
|
||||
if (Node->Right)
|
||||
RightVal = AssembleTree(Node->Right, LeftVal, LoopBeginLabel, LoopEndLabel, Node->Operation);
|
||||
|
||||
switch (Node->Operation) {
|
||||
case OP_ADD:
|
||||
|
||||
case OP_SUBTRACT:
|
||||
|
||||
case OP_MULTIPLY:
|
||||
|
||||
case OP_DIVIDE:
|
||||
|
||||
case OP_SCALE:
|
||||
switch (Node->Size) {
|
||||
case 2:
|
||||
case 4:
|
||||
case 8:
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
case OP_BREAK:
|
||||
|
||||
case OP_CONTINUE:
|
||||
|
||||
case OP_ADDRESS:
|
||||
|
||||
case OP_DEREF:
|
||||
|
||||
case OP_ASSIGN:
|
||||
printf("Preparing for assignment..\r\n");
|
||||
if (Node->Right == NULL)
|
||||
Die("Fault in assigning a null rvalue");
|
||||
|
||||
printf("\tCalculating assignment for target %s:\r\n", Node->Right->Symbol->Name);
|
||||
switch (Node->Right->Operation) {
|
||||
case REF_IDENT:
|
||||
if (Node->Right->Symbol->Storage == SC_LOCAL) (void)0;
|
||||
|
||||
case OP_DEREF:
|
||||
default:
|
||||
DieDecimal("Can't ASSIGN in AssembleTree: ", Node->Operation);
|
||||
}; return 0;
|
||||
|
||||
case OP_WIDEN:
|
||||
|
||||
case OP_RET:
|
||||
|
||||
case OP_EQUAL:
|
||||
case OP_INEQ:
|
||||
case OP_LESS:
|
||||
case OP_GREAT:
|
||||
case OP_LESSE:
|
||||
case OP_GREATE:
|
||||
if (ParentOp == OP_IF || ParentOp == OP_LOOP) (void)0;
|
||||
|
||||
|
||||
case REF_IDENT:
|
||||
if (TypeIsPtr(Node->ExprType)) {
|
||||
}
|
||||
|
||||
if (Node->RVal || ParentOp == OP_DEREF) {
|
||||
if (Node->Symbol->Storage == SC_LOCAL || Node->Symbol->Storage == SC_PARAM) (void)0;
|
||||
} else
|
||||
return -1;
|
||||
|
||||
case TERM_INTLITERAL:
|
||||
|
||||
case TERM_STRLITERAL:
|
||||
|
||||
case OP_PRINT:
|
||||
|
||||
case OP_BITAND:
|
||||
|
||||
case OP_BITOR:
|
||||
|
||||
case OP_BITXOR:
|
||||
|
||||
case OP_SHIFTL:
|
||||
|
||||
case OP_SHIFTR:
|
||||
|
||||
case OP_POSTINC:
|
||||
if (Node->Symbol->Storage == SC_LOCAL || Node->Symbol->Storage == SC_PARAM) (void)0;
|
||||
|
||||
case OP_POSTDEC:
|
||||
if (Node->Symbol->Storage == SC_LOCAL || Node->Symbol->Storage == SC_PARAM) (void)0;
|
||||
|
||||
case OP_PREINC:
|
||||
if (Node->Symbol->Storage == SC_LOCAL || Node->Symbol->Storage == SC_PARAM) (void)0;
|
||||
|
||||
case OP_PREDEC:
|
||||
if (Node->Symbol->Storage == SC_LOCAL || Node->Symbol->Storage == SC_PARAM) (void)0;
|
||||
|
||||
case OP_BOOLNOT:
|
||||
|
||||
case OP_BITNOT:
|
||||
|
||||
case OP_NEGATE:
|
||||
|
||||
case OP_BOOLCONV:
|
||||
return 0;
|
||||
|
||||
default:
|
||||
DieDecimal("Unknown ASM Operation", Node->Operation);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct AssemblerVtable QBEAssemblerVtable = {
|
||||
.AssembleTree = AssembleTree
|
||||
};
|
||||
|
||||
static const struct AssemblerModule QBEAssemblerModule = {
|
||||
.name = "QBE",
|
||||
.vtable = &QBEAssemblerVtable
|
||||
};
|
||||
|
||||
|
||||
void RegisterQBE() {
|
||||
RegisterModule(&QBEAssemblerModule);
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
int :: printf(char* format);
|
||||
import "print.em"
|
||||
|
||||
int :: main () {
|
||||
printf("%s\r\n", "hi there");
|
||||
|
|
5
tests/test.java
Normal file
5
tests/test.java
Normal file
|
@ -0,0 +1,5 @@
|
|||
class Test {
|
||||
public static void main(String[] args) {
|
||||
java.lang.System.out.println("hi");
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user