Refactor to generalise assembler output
This commit is contained in:
parent
39756f4e89
commit
216d6c6b5e
|
@ -8,7 +8,9 @@ include_directories(include)
|
||||||
add_executable(Erythro
|
add_executable(Erythro
|
||||||
include/Data.h
|
include/Data.h
|
||||||
include/Defs.h
|
include/Defs.h
|
||||||
src/Assembler.c
|
src/assemble/AssemblerDispatcher.c
|
||||||
|
src/assemble/ASMAssembler.c
|
||||||
|
src/assemble/QBEAssembler.c
|
||||||
src/Delegate.c
|
src/Delegate.c
|
||||||
src/Dump.c
|
src/Dump.c
|
||||||
src/Lexer.c
|
src/Lexer.c
|
||||||
|
@ -18,4 +20,5 @@ add_executable(Erythro
|
||||||
src/Statements.c
|
src/Statements.c
|
||||||
src/Symbols.c
|
src/Symbols.c
|
||||||
src/Types.c
|
src/Types.c
|
||||||
src/Importer.c)
|
src/Importer.c
|
||||||
|
src/assemble/JVMAssembler.c)
|
||||||
|
|
|
@ -48,6 +48,10 @@ extern_ bool OptVerboseOutput;
|
||||||
extern_ char* OutputFileName;
|
extern_ char* OutputFileName;
|
||||||
// The sizes of each of the core types, in bytes.
|
// The sizes of each of the core types, in bytes.
|
||||||
extern_ int TypeSizes[5];
|
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.
|
// The names of each token in the language, synchronized to the TokenTypes enum.
|
||||||
extern_ char* TokenNames[];
|
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 * * * *
|
* * * * 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);
|
// Module List
|
||||||
|
void RegisterQBE();
|
||||||
int AsLdLocalVar(struct SymbolTableEntry* Entry, int Operation);
|
void RegisterWin32ASM();
|
||||||
|
void RegisterJVM();
|
||||||
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);
|
|
||||||
|
|
||||||
|
|
||||||
/* * * * * * * * * * * * * * * * * * * * * * *
|
/* * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
|
|
@ -95,7 +95,7 @@ void Compile(struct FileData* InputFile) {
|
||||||
|
|
||||||
Tokenise();
|
Tokenise();
|
||||||
|
|
||||||
AssemblerPreamble();
|
Assembler->vtable->AssemblerPreamble();
|
||||||
|
|
||||||
ParseGlobals();
|
ParseGlobals();
|
||||||
|
|
||||||
|
|
12
src/Main.c
12
src/Main.c
|
@ -107,6 +107,7 @@ int main(int argc, char* argv[]) {
|
||||||
OptAssembleFiles = true;
|
OptAssembleFiles = true;
|
||||||
OptLinkFiles = true;
|
OptLinkFiles = true;
|
||||||
OptVerboseOutput = false;
|
OptVerboseOutput = false;
|
||||||
|
OptAssemblerName = "Win32 GAS ASM";
|
||||||
|
|
||||||
// Temporary .o storage and counter
|
// Temporary .o storage and counter
|
||||||
int ObjectCount = 0;
|
int ObjectCount = 0;
|
||||||
|
@ -126,24 +127,32 @@ int main(int argc, char* argv[]) {
|
||||||
switch (argv[i][j]) {
|
switch (argv[i][j]) {
|
||||||
case 'o': // output
|
case 'o': // output
|
||||||
OutputFileName = argv[++i];
|
OutputFileName = argv[++i];
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'T': // print Tree (debug)
|
case 'T': // print Tree (debug)
|
||||||
OptDumpTree = true;
|
OptDumpTree = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'c': // Compile only
|
case 'c': // Compile only
|
||||||
OptAssembleFiles = true;
|
OptAssembleFiles = true;
|
||||||
OptKeepAssembly = false;
|
OptKeepAssembly = false;
|
||||||
OptLinkFiles = false;
|
OptLinkFiles = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'S': // aSsemble only
|
case 'S': // aSsemble only
|
||||||
OptAssembleFiles = true;
|
OptAssembleFiles = true;
|
||||||
OptKeepAssembly = true;
|
OptKeepAssembly = true;
|
||||||
OptLinkFiles = false;
|
OptLinkFiles = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'v': // Verbose output
|
case 'v': // Verbose output
|
||||||
OptVerboseOutput = true;
|
OptVerboseOutput = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'm': // Specify Assembler Module
|
||||||
|
OptAssemblerName = argv[++i];
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
DisplayUsage(argv[0]);
|
DisplayUsage(argv[0]);
|
||||||
}
|
}
|
||||||
|
@ -159,6 +168,7 @@ int main(int argc, char* argv[]) {
|
||||||
Files = malloc(sizeof(struct FileData*) * (argc - i) + 1);
|
Files = malloc(sizeof(struct FileData*) * (argc - i) + 1);
|
||||||
memset(Files, 0, 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.
|
// For the rest of the files specified, we can iterate them right to left.
|
||||||
while (i < argc) {
|
while (i < argc) {
|
||||||
|
|
|
@ -241,7 +241,7 @@ struct ASTNode* ParsePrimary(void) {
|
||||||
|
|
||||||
case LI_STR:
|
case LI_STR:
|
||||||
|
|
||||||
ID = AsNewString(CurrentIdentifier);
|
ID = Assembler->vtable->AsNewString(CurrentIdentifier);
|
||||||
Node = ConstructASTLeaf(TERM_STRLITERAL, PointerTo(RET_CHAR), NULL, ID);
|
Node = ConstructASTLeaf(TERM_STRLITERAL, PointerTo(RET_CHAR), NULL, ID);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -621,7 +621,7 @@ void ParseGlobals() {
|
||||||
Tree = ParseFunction(Type);
|
Tree = ParseFunction(Type);
|
||||||
if (Tree && CurrentFile->AllowDefinitions) {
|
if (Tree && CurrentFile->AllowDefinitions) {
|
||||||
printf("\nBeginning assembler creation of new function %s\n", Tree->Symbol->Name);
|
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();
|
FreeLocals();
|
||||||
} else {
|
} else {
|
||||||
printf("\nFunction prototype saved\r\n");
|
printf("\nFunction prototype saved\r\n");
|
||||||
|
|
|
@ -110,7 +110,7 @@ struct SymbolTableEntry* BeginCompositeDeclaration(int Type) {
|
||||||
|
|
||||||
for (Member = Member->NextSymbol; Member != NULL; Member = Member->NextSymbol) {
|
for (Member = Member->NextSymbol; Member != NULL; Member = Member->NextSymbol) {
|
||||||
if (Type == DAT_STRUCT)
|
if (Type == DAT_STRUCT)
|
||||||
Member->SinkOffset = AsAlignMemory(Member->Type, Offset, 1);
|
Member->SinkOffset = Assembler->vtable->AsAlignMemory(Member->Type, Offset, 1);
|
||||||
else
|
else
|
||||||
Member->SinkOffset = 0;
|
Member->SinkOffset = 0;
|
||||||
|
|
||||||
|
|
|
@ -257,7 +257,7 @@ struct SymbolTableEntry* AddSymbol(char* Name, int Type, int Structure, int Stor
|
||||||
case SC_GLOBAL:
|
case SC_GLOBAL:
|
||||||
AppendSymbol(&Globals, &GlobalsEnd, Node);
|
AppendSymbol(&Globals, &GlobalsEnd, Node);
|
||||||
// We don't want to generate a static block for functions.
|
// 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;
|
break;
|
||||||
case SC_STRUCT:
|
case SC_STRUCT:
|
||||||
AppendSymbol(&Structs, &StructsEnd, Node);
|
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 () {
|
int :: main () {
|
||||||
printf("%s\r\n", "hi there");
|
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