Major rewrite of the symbol parsing
Moved from a static double-ended list to individual singly-linked lists for easier and faster parsing
This commit is contained in:
parent
a52779e379
commit
eb118db872
|
@ -15,7 +15,9 @@
|
|||
#define TEXTLEN 512
|
||||
#define SYMBOLS 1024
|
||||
|
||||
extern_ struct SymbolTable Symbols[SYMBOLS];
|
||||
extern_ struct SymbolTableEntry* Globals, *GlobalsEnd;
|
||||
extern_ struct SymbolTableEntry* Locals, *LocalsEnd;
|
||||
extern_ struct SymbolTableEntry* Params, *ParamsEnd;
|
||||
|
||||
extern_ bool OptDumpTree;
|
||||
extern_ bool OptKeepAssembly;
|
||||
|
@ -26,12 +28,12 @@ extern_ bool OptVerboseOutput;
|
|||
extern_ char* OutputFileName;
|
||||
extern_ char* CurrentASMFile, *CurrentObjectFile;
|
||||
|
||||
extern_ int TypeSizes[9];
|
||||
extern_ char* TypeNames[9];
|
||||
extern_ int TypeSizes[5];
|
||||
|
||||
extern_ char* TokenNames[];
|
||||
|
||||
extern_ int CurrentFunction;
|
||||
extern_ struct SymbolTableEntry* FunctionEntry;
|
||||
extern_ int Line;
|
||||
extern_ int Overread;
|
||||
|
||||
|
|
|
@ -174,11 +174,12 @@ struct ASTNode {
|
|||
struct ASTNode* Left;
|
||||
struct ASTNode* Middle;
|
||||
struct ASTNode* Right;
|
||||
struct SymbolTableEntry* Symbol;
|
||||
union {
|
||||
int Size; // OP_SCALE's linear representation
|
||||
int IntValue; // TERM_INTLIT's Value
|
||||
int ID; // LV_IDENT's Symbols[] index.
|
||||
} Value;
|
||||
};
|
||||
};
|
||||
|
||||
struct Token {
|
||||
|
@ -191,14 +192,25 @@ struct Token {
|
|||
* assorted goodies.
|
||||
*/
|
||||
|
||||
struct SymbolTable {
|
||||
struct SymbolTableEntry {
|
||||
char* Name;
|
||||
int Type; // An entry in DataTypes, referring to the type of this data
|
||||
struct SymbolTableEntry* CompositeType; // A pointer to the start of a Symbol Table list that represents a certain Composite type
|
||||
int Structure; // An entry in StructureType - metadata on how to process the data
|
||||
int EndLabel; // The number of the label to jump to, in order to exit this function (if applicable)
|
||||
int Length; // The length of the symbol in units of 1 element -- the size of an array, for example.
|
||||
int Storage; // The scope of this symbol - decides when it is discarded.
|
||||
int SinkOffset; // How many times must we sink the rbp to get to this symbol in the stack?
|
||||
union {
|
||||
int EndLabel; // For a function - The number of the label to jump to, in order to exit this function (if applicable)
|
||||
int Length; // For an array - The length of the symbol in units of 1 element -- the size of an array, for example.
|
||||
int IntValue; // For an enum - The value of an Enum entry
|
||||
};
|
||||
|
||||
union {
|
||||
int SinkOffset; // For a variable - How many times must we sink the rbp to get to this symbol in the stack?
|
||||
int Elements; // For a function - How many parameters?
|
||||
};
|
||||
|
||||
struct SymbolTableEntry* NextSymbol; // The next symbol in a list
|
||||
struct SymbolTableEntry* Start; // The first member in a list
|
||||
};
|
||||
|
||||
enum StorageScope {
|
||||
|
@ -212,22 +224,23 @@ enum StorageScope {
|
|||
|
||||
|
||||
/*
|
||||
* The primitive data types for the language
|
||||
* //TODO: Move back into TokenTypes
|
||||
* The types of data being held in memory.
|
||||
* The lowest 4 bits of these enum values
|
||||
* encode a nested pointer type.
|
||||
*
|
||||
* This meaning, a single enum can hold
|
||||
* ****************int types.
|
||||
* Should be enough for everyone, right?
|
||||
*/
|
||||
enum DataTypes {
|
||||
RET_NONE, // No return type. Literal void.
|
||||
RET_CHAR, // "char" type keyword
|
||||
RET_INT, // "int" type keyword
|
||||
RET_LONG, // "long" type keyword
|
||||
RET_VOID, // "void" type keyword
|
||||
|
||||
// Pointer types
|
||||
PTR_CHAR,
|
||||
PTR_INT,
|
||||
PTR_LONG,
|
||||
PTR_VOID,
|
||||
|
||||
RET_NONE, // No return type. Literal void.
|
||||
RET_CHAR = 16, // "char" type keyword
|
||||
RET_INT = 32, // "int" type keyword
|
||||
RET_LONG = 48, // "long" type keyword
|
||||
RET_VOID = 64, // "void" type keyword
|
||||
|
||||
DAT_STRUCT = 80, // Struct Data
|
||||
DAT_UNION, // Union Data
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -278,6 +291,8 @@ struct ASTNode* MutateType(struct ASTNode* Tree, int RightType, int Operation);
|
|||
int TypeIsInt(int Type);
|
||||
int TypeIsPtr(int Type);
|
||||
|
||||
char* TypeNames(int Type);
|
||||
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* * * * * * S Y N T A X T R E E * * * * * *
|
||||
|
@ -288,11 +303,12 @@ struct ASTNode* ConstructASTNode(int Operation, int Type,
|
|||
struct ASTNode* Left,
|
||||
struct ASTNode* Middle,
|
||||
struct ASTNode* Right,
|
||||
struct SymbolTableEntry* Symbol,
|
||||
int IntValue);
|
||||
|
||||
struct ASTNode* ConstructASTLeaf(int Operation, int Type, int IntValue);
|
||||
struct ASTNode* ConstructASTLeaf(int Operation, int Type, struct SymbolTableEntry* Symbol, int IntValue);
|
||||
|
||||
struct ASTNode* ConstructASTBranch(int Operation, int Type, struct ASTNode* Left, int IntValue);
|
||||
struct ASTNode* ConstructASTBranch(int Operation, int Type, struct ASTNode* Left, struct SymbolTableEntry* Symbol, int IntValue);
|
||||
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
|
@ -336,11 +352,17 @@ struct ASTNode* PrintStatement(void);
|
|||
* * * * * * S Y M B O L T A B L E * * * * * *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
int FindSymbol(char* Symbol);
|
||||
struct SymbolTableEntry* FindSymbol(char* Symbol);
|
||||
struct SymbolTableEntry* FindLocal(char* Symbol);
|
||||
struct SymbolTableEntry* FindGlobal(char* Symbol);
|
||||
|
||||
int AddSymbol(char* Name, int Type, int Structure, int Storage, int EndLabel, int Length);
|
||||
void AppendSymbol(struct SymbolTableEntry** Head, struct SymbolTableEntry** Tail, struct SymbolTableEntry* Node);
|
||||
|
||||
void FreeLocals();
|
||||
void ClearTables();
|
||||
|
||||
struct SymbolTableEntry* AddSymbol(char* Name, int Type, int Structure, int Storage, int Length, int SinkOffset);
|
||||
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* * * * C O N T R O L S T A T U S * * * *
|
||||
|
@ -375,19 +397,19 @@ int AsMul(int Left, int Right);
|
|||
int AsSub(int Left, int Right);
|
||||
int AsDiv(int Left, int Right);
|
||||
|
||||
int AsLdGlobalVar(int ID, int Operation);
|
||||
int AsLdLocalVar(int ID, int Operation);
|
||||
int AsStrGlobalVar(int Register, int ID);
|
||||
int AsStrLocalVar(int Register, int ID);
|
||||
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(int ID);
|
||||
int AsAddr(struct SymbolTableEntry* Entry);
|
||||
|
||||
void AsGlobalSymbol(int ID);
|
||||
void AsGlobalSymbol(struct SymbolTableEntry* Entry);
|
||||
int AsNewString(char* Value);
|
||||
|
||||
|
||||
|
@ -420,25 +442,25 @@ void AsLabel(int Label);
|
|||
|
||||
int AsShl(int Register, int Val);
|
||||
|
||||
int AsReturn(int Register, int FuncID);
|
||||
int AsReturn(struct SymbolTableEntry* Entry, int Register);
|
||||
int AsCallWrapper(struct ASTNode* Node);
|
||||
void AsCopyArgs(int Register, int Position);
|
||||
int AsCall(int Register, int FuncID);
|
||||
int AsCall(struct SymbolTableEntry* Entry, int Args);
|
||||
|
||||
int AsWhile(struct ASTNode* Node);
|
||||
|
||||
void AssemblerPrint(int Register);
|
||||
|
||||
void AssemblerPreamble();
|
||||
void AsFunctionPreamble(int ID);
|
||||
void AsFunctionEpilogue(int ID);
|
||||
void AsFunctionPreamble(struct SymbolTableEntry* Entry);
|
||||
void AsFunctionEpilogue(struct SymbolTableEntry* Entry);
|
||||
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * *
|
||||
* * * * D E C L A R A T I O N * * * *
|
||||
* * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
void BeginVariableDeclaration(int Type, int Scope);
|
||||
struct SymbolTableEntry* BeginVariableDeclaration(int Type, int Scope);
|
||||
struct ASTNode* ParseIdentifier(void);
|
||||
|
||||
struct ASTNode* IfStatement();
|
||||
|
|
280
src/Assembler.c
280
src/Assembler.c
|
@ -70,9 +70,9 @@ int AssembleTree(struct ASTNode* Node, int Register, int ParentOp) {
|
|||
return (AsCallWrapper(Node));
|
||||
|
||||
case OP_FUNC:
|
||||
AsFunctionPreamble(Node->Value.ID);
|
||||
AsFunctionPreamble(Node->Symbol);
|
||||
AssembleTree(Node->Left, -1, Node->Operation);
|
||||
AsFunctionEpilogue(Node->Value.ID);
|
||||
AsFunctionEpilogue(Node->Symbol);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -107,17 +107,17 @@ int AssembleTree(struct ASTNode* Node, int Register, int ParentOp) {
|
|||
case OP_SCALE:
|
||||
// We can (ab)use the powers of 2 to do
|
||||
// efficient scaling with bitshifting.
|
||||
switch(Node->Value.Size) {
|
||||
switch(Node->Size) {
|
||||
case 2: return AsShl(LeftVal, 1);
|
||||
case 4: return AsShl(LeftVal, 2);
|
||||
case 8: return AsShl(LeftVal, 3);
|
||||
|
||||
default:
|
||||
RightVal = AsLoad(Node->Value.Size);
|
||||
RightVal = AsLoad(Node->Size);
|
||||
return AsMul(LeftVal, RightVal);
|
||||
}
|
||||
case OP_ADDRESS:
|
||||
return AsAddr(Node->Value.ID);
|
||||
return AsAddr(Node->Symbol);
|
||||
|
||||
case OP_DEREF:
|
||||
return Node->RVal ? AsDeref(LeftVal, Node->Left->ExprType) : LeftVal;
|
||||
|
@ -127,13 +127,13 @@ int AssembleTree(struct ASTNode* Node, int Register, int ParentOp) {
|
|||
if(Node->Right == NULL)
|
||||
Die("Fault in assigning a null rvalue");
|
||||
|
||||
printf("\tCalculating assignment for target %s:%d\r\n", Symbols[Node->Right->Value.ID].Name, Node->Right->Value.ID);
|
||||
printf("\tCalculating assignment for target %s:\r\n", Node->Right->Symbol->Name);
|
||||
switch(Node->Right->Operation) {
|
||||
case REF_IDENT:
|
||||
if(Symbols[Node->Right->Value.ID].Storage == SC_LOCAL)
|
||||
return AsStrLocalVar(LeftVal, Node->Right->Value.ID);
|
||||
if(Node->Right->Symbol->Storage == SC_LOCAL)
|
||||
return AsStrLocalVar(Node->Right->Symbol, LeftVal);
|
||||
else
|
||||
return AsStrGlobalVar(LeftVal, Node->Right->Value.ID);
|
||||
return AsStrGlobalVar(Node->Right->Symbol, LeftVal);
|
||||
|
||||
case OP_DEREF: return AsStrDeref(LeftVal, RightVal, Node->Right->ExprType);
|
||||
default: DieDecimal("Can't ASSIGN in AssembleTree: ", Node->Operation);
|
||||
|
@ -144,8 +144,8 @@ int AssembleTree(struct ASTNode* Node, int Register, int ParentOp) {
|
|||
return LeftVal; //AsWiden(LeftVal, Node->Left->ExprType, Node->ExprType);
|
||||
|
||||
case OP_RET:
|
||||
printf("\tReturning from %s, %d\n", Symbols[Node->Value.ID].Name, Node->Value.ID);
|
||||
AsReturn(LeftVal, CurrentFunction);
|
||||
printf("\tReturning from %s\n", Node->Symbol->Name);
|
||||
AsReturn(FunctionEntry, LeftVal);
|
||||
return -1;
|
||||
|
||||
/* case OP_EQUAL:
|
||||
|
@ -181,18 +181,18 @@ int AssembleTree(struct ASTNode* Node, int Register, int ParentOp) {
|
|||
case REF_IDENT:
|
||||
//printf("\tReferencing variable %s %s with type %s and storage %d\r\n", Symbols[Node->Value.ID].Name, Node->RVal ? " rval " : "", ParentOp, Symbols[Node->Value.ID].Storage);
|
||||
if(Node->RVal || ParentOp == OP_DEREF) {
|
||||
if(Symbols[Node->Value.ID].Storage == SC_LOCAL || Symbols[Node->Value.ID].Storage == SC_PARAM)
|
||||
return AsLdLocalVar(Node->Value.ID, Node->Operation);
|
||||
if(Node->Symbol->Storage == SC_LOCAL || Node->Symbol->Storage == SC_PARAM)
|
||||
return AsLdLocalVar(Node->Symbol, Node->Operation);
|
||||
else
|
||||
return AsLdGlobalVar(Node->Value.ID, Node->Operation);
|
||||
return AsLdGlobalVar(Node->Symbol, Node->Operation);
|
||||
} else
|
||||
return -1;
|
||||
|
||||
case TERM_INTLITERAL:
|
||||
return AsLoad(Node->Value.IntValue);
|
||||
return AsLoad(Node->IntValue);
|
||||
|
||||
case TERM_STRLITERAL:
|
||||
return AsLoadString(Node->Value.ID);
|
||||
return AsLoadString(Node->IntValue);
|
||||
|
||||
case OP_PRINT:
|
||||
AssemblerPrint(LeftVal);
|
||||
|
@ -220,16 +220,16 @@ int AssembleTree(struct ASTNode* Node, int Register, int ParentOp) {
|
|||
return AsShiftRight(LeftVal, RightVal);
|
||||
|
||||
case OP_POSTINC:
|
||||
return AsLdGlobalVar(Node->Value.IntValue, Node->Operation);
|
||||
return AsLdGlobalVar(Node->Symbol, Node->Operation);
|
||||
|
||||
case OP_POSTDEC:
|
||||
return AsLdGlobalVar(Node->Value.IntValue, Node->Operation);
|
||||
return AsLdGlobalVar(Node->Symbol, Node->Operation);
|
||||
|
||||
case OP_PREINC:
|
||||
return AsLdGlobalVar(Node->Value.IntValue, Node->Operation);
|
||||
return AsLdGlobalVar(Node->Symbol, Node->Operation);
|
||||
|
||||
case OP_PREDEC:
|
||||
return AsLdGlobalVar(Node->Value.IntValue, Node->Operation);
|
||||
return AsLdGlobalVar(Node->Symbol, Node->Operation);
|
||||
|
||||
case OP_BOOLNOT:
|
||||
return AsBooleanNOT(LeftVal);
|
||||
|
@ -473,225 +473,217 @@ int AsShl(int Register, int Val) {
|
|||
return Register;
|
||||
}
|
||||
|
||||
int AsLdGlobalVar(int ID, int Operation) {
|
||||
int AsLdGlobalVar(struct SymbolTableEntry* Entry, int Operation) {
|
||||
int Reg = RetrieveRegister();
|
||||
|
||||
printf("\tStoring %s's contents into %s, globally\n", Symbols[ID].Name, Registers[Reg]);
|
||||
printf("\tStoring %s's contents into %s, globally\n", Entry->Name, Registers[Reg]);
|
||||
|
||||
switch(Symbols[ID].Type) {
|
||||
case RET_CHAR:
|
||||
int TypeSize = PrimitiveSize(Entry->Type);
|
||||
switch(TypeSize) {
|
||||
case 1:
|
||||
switch(Operation) {
|
||||
case OP_PREINC:
|
||||
fprintf(OutputFile, "\tincb\t%s(\%%rip)\n", Symbols[ID].Name); break;
|
||||
fprintf(OutputFile, "\tincb\t%s(\%%rip)\n", Entry->Name); break;
|
||||
case OP_PREDEC:
|
||||
fprintf(OutputFile, "\tdecb\t%s(\%%rip)\n", Symbols[ID].Name); break;
|
||||
fprintf(OutputFile, "\tdecb\t%s(\%%rip)\n", Entry->Name); break;
|
||||
}
|
||||
|
||||
fprintf(OutputFile, "\tmovzbq\t%s(\%%rip), %s\n", Symbols[ID].Name, Registers[Reg]);
|
||||
fprintf(OutputFile, "\tmovzbq\t%s(\%%rip), %s\n", Entry->Name, Registers[Reg]);
|
||||
|
||||
switch(Operation) {
|
||||
case OP_POSTINC:
|
||||
fprintf(OutputFile, "\tincb\t%s(\%%rip)\n", Symbols[ID].Name); break;
|
||||
fprintf(OutputFile, "\tincb\t%s(\%%rip)\n", Entry->Name); break;
|
||||
case OP_POSTDEC:
|
||||
fprintf(OutputFile, "\tdecb\t%s(\%%rip)\n", Symbols[ID].Name); break;
|
||||
fprintf(OutputFile, "\tdecb\t%s(\%%rip)\n", Entry->Name); break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case RET_INT:
|
||||
case 4:
|
||||
switch(Operation) {
|
||||
case OP_PREINC:
|
||||
fprintf(OutputFile, "\tincl\t%s(\%%rip)\n", Symbols[ID].Name); break;
|
||||
fprintf(OutputFile, "\tincl\t%s(\%%rip)\n", Entry->Name); break;
|
||||
case OP_PREDEC:
|
||||
fprintf(OutputFile, "\tdecl\t%s(\%%rip)\n", Symbols[ID].Name); break;
|
||||
fprintf(OutputFile, "\tdecl\t%s(\%%rip)\n", Entry->Name); break;
|
||||
}
|
||||
|
||||
fprintf(OutputFile, "\tmovslq\t%s(\%%rip), %s\n", Symbols[ID].Name, Registers[Reg]);
|
||||
fprintf(OutputFile, "\tmovslq\t%s(\%%rip), %s\n", Entry->Name, Registers[Reg]);
|
||||
|
||||
switch(Operation) {
|
||||
case OP_POSTINC:
|
||||
fprintf(OutputFile, "\tincl\t%s(\%%rip)\n", Symbols[ID].Name); break;
|
||||
fprintf(OutputFile, "\tincl\t%s(\%%rip)\n", Entry->Name); break;
|
||||
case OP_POSTDEC:
|
||||
fprintf(OutputFile, "\tdecl\t%s(\%%rip)\n", Symbols[ID].Name); break;
|
||||
fprintf(OutputFile, "\tdecl\t%s(\%%rip)\n", Entry->Name); break;
|
||||
}
|
||||
|
||||
break;
|
||||
case RET_LONG:
|
||||
case PTR_CHAR:
|
||||
case PTR_INT:
|
||||
case PTR_LONG:
|
||||
case PTR_VOID:
|
||||
case 8:
|
||||
switch(Operation) {
|
||||
case OP_PREINC:
|
||||
fprintf(OutputFile, "\tincq\t%s(\%%rip)\n", Symbols[ID].Name); break;
|
||||
fprintf(OutputFile, "\tincq\t%s(\%%rip)\n", Entry->Name); break;
|
||||
case OP_PREDEC:
|
||||
fprintf(OutputFile, "\tdecq\t%s(\%%rip)\n", Symbols[ID].Name); break;
|
||||
fprintf(OutputFile, "\tdecq\t%s(\%%rip)\n", Entry->Name); break;
|
||||
}
|
||||
|
||||
fprintf(OutputFile, "\tmovq\t%s(\%%rip), %s\n", Symbols[ID].Name, Registers[Reg]);
|
||||
fprintf(OutputFile, "\tmovq\t%s(\%%rip), %s\n", Entry->Name, Registers[Reg]);
|
||||
|
||||
switch(Operation) {
|
||||
case OP_POSTINC:
|
||||
fprintf(OutputFile, "\tincq\t%s(\%%rip)\n", Symbols[ID].Name); break;
|
||||
fprintf(OutputFile, "\tincq\t%s(\%%rip)\n", Entry->Name); break;
|
||||
case OP_POSTDEC:
|
||||
fprintf(OutputFile, "\tdecq\t%s(\%%rip)\n", Symbols[ID].Name); break;
|
||||
fprintf(OutputFile, "\tdecq\t%s(\%%rip)\n", Entry->Name); break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
DieMessage("Bad type for loading", TypeNames[Symbols[ID].Type]);
|
||||
DieMessage("Bad type for loading", TypeNames(Entry->Type));
|
||||
}
|
||||
|
||||
return Reg;
|
||||
}
|
||||
|
||||
int AsStrGlobalVar(int Register, int ID) {
|
||||
printf("\tStoring contents of %s into %s, type %d, globally: ID %d\n", Registers[Register], Symbols[ID].Name, Symbols[ID].Type, ID);
|
||||
int AsStrGlobalVar(struct SymbolTableEntry* Entry, int Register) {
|
||||
printf("\tStoring contents of %s into %s, type %d, globally:\n", Registers[Register], Entry->Name, Entry->Type);
|
||||
|
||||
switch(Symbols[ID].Type) {
|
||||
case RET_CHAR:
|
||||
int TypeSize = PrimitiveSize(Entry->Type);
|
||||
switch(TypeSize) {
|
||||
case 1:
|
||||
// movzbq zeroes, then moves a byte into the quad register
|
||||
fprintf(OutputFile, "\tmovb\t%s, %s(\%%rip)\n", ByteRegisters[Register], Symbols[ID].Name);
|
||||
fprintf(OutputFile, "\tmovb\t%s, %s(\%%rip)\n", ByteRegisters[Register], Entry->Name);
|
||||
break;
|
||||
|
||||
case RET_INT:
|
||||
fprintf(OutputFile, "\tmovl\t%s, %s(\%%rip)\n", DoubleRegisters[Register], Symbols[ID].Name);
|
||||
case 4:
|
||||
fprintf(OutputFile, "\tmovl\t%s, %s(\%%rip)\n", DoubleRegisters[Register], Entry->Name);
|
||||
break;
|
||||
|
||||
case RET_LONG:
|
||||
case PTR_CHAR:
|
||||
case PTR_INT:
|
||||
case PTR_LONG:
|
||||
case PTR_VOID:
|
||||
fprintf(OutputFile, "\tmovq\t%s, %s(%%rip)\n", Registers[Register], Symbols[ID].Name);
|
||||
case 8:
|
||||
fprintf(OutputFile, "\tmovq\t%s, %s(%%rip)\n", Registers[Register], Entry->Name);
|
||||
break;
|
||||
|
||||
default:
|
||||
DieMessage("Bad type for saving", TypeNames[Symbols[ID].Type]);
|
||||
DieMessage("Bad type for saving", TypeNames(Entry->Type));
|
||||
}
|
||||
|
||||
return Register;
|
||||
}
|
||||
|
||||
int AsLdLocalVar(int ID, int Operation) {
|
||||
int AsLdLocalVar(struct SymbolTableEntry* Entry, int Operation) {
|
||||
int Reg = RetrieveRegister();
|
||||
|
||||
printf("\tStoring the var at %d's contents into %s, locally\n", Symbols[ID].SinkOffset, Registers[Reg]);
|
||||
|
||||
switch(Symbols[ID].Type) {
|
||||
case RET_CHAR:
|
||||
printf("\tStoring the var at %d's contents into %s, locally\n", Entry->SinkOffset, Registers[Reg]);
|
||||
|
||||
int TypeSize = PrimitiveSize(Entry->Type);
|
||||
switch(TypeSize) {
|
||||
case 1:
|
||||
switch(Operation) {
|
||||
case OP_PREINC:
|
||||
fprintf(OutputFile, "\tincb\t%d(\%%rbp)\n", Symbols[ID].SinkOffset); break;
|
||||
fprintf(OutputFile, "\tincb\t%d(\%%rbp)\n", Entry->SinkOffset); break;
|
||||
case OP_PREDEC:
|
||||
fprintf(OutputFile, "\tdecb\t%d(\%%rbp)\n", Symbols[ID].SinkOffset); break;
|
||||
fprintf(OutputFile, "\tdecb\t%d(\%%rbp)\n", Entry->SinkOffset); break;
|
||||
}
|
||||
|
||||
fprintf(OutputFile, "\tmovzbq\t%d(\%%rbp), %s\n", Symbols[ID].SinkOffset, Registers[Reg]);
|
||||
fprintf(OutputFile, "\tmovzbq\t%d(\%%rbp), %s\n", Entry->SinkOffset, Registers[Reg]);
|
||||
|
||||
switch(Operation) {
|
||||
case OP_POSTINC:
|
||||
fprintf(OutputFile, "\tincb\t%d(\%%rbp)\n", Symbols[ID].SinkOffset); break;
|
||||
fprintf(OutputFile, "\tincb\t%d(\%%rbp)\n", Entry->SinkOffset); break;
|
||||
case OP_POSTDEC:
|
||||
fprintf(OutputFile, "\tdecb\t%d(\%%rbp)\n", Symbols[ID].SinkOffset); break;
|
||||
fprintf(OutputFile, "\tdecb\t%d(\%%rbp)\n", Entry->SinkOffset); break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case RET_INT:
|
||||
case 4:
|
||||
switch(Operation) {
|
||||
case OP_PREINC:
|
||||
fprintf(OutputFile, "\tincl\t%d(\%%rbp)\n", Symbols[ID].SinkOffset); break;
|
||||
fprintf(OutputFile, "\tincl\t%d(\%%rbp)\n", Entry->SinkOffset); break;
|
||||
case OP_PREDEC:
|
||||
fprintf(OutputFile, "\tdecl\t%d(\%%rbp)\n", Symbols[ID].SinkOffset); break;
|
||||
fprintf(OutputFile, "\tdecl\t%d(\%%rbp)\n", Entry->SinkOffset); break;
|
||||
}
|
||||
|
||||
fprintf(OutputFile, "\tmovslq\t%d(\%%rbp), %s\n", Symbols[ID].SinkOffset, Registers[Reg]);
|
||||
fprintf(OutputFile, "\tmovslq\t%d(\%%rbp), %s\n", Entry->SinkOffset, Registers[Reg]);
|
||||
|
||||
switch(Operation) {
|
||||
case OP_POSTINC:
|
||||
fprintf(OutputFile, "\tincl\t%d(\%%rbp)\n", Symbols[ID].SinkOffset); break;
|
||||
fprintf(OutputFile, "\tincl\t%d(\%%rbp)\n", Entry->SinkOffset); break;
|
||||
case OP_POSTDEC:
|
||||
fprintf(OutputFile, "\tdecl\t%d(\%%rbp)\n", Symbols[ID].SinkOffset); break;
|
||||
fprintf(OutputFile, "\tdecl\t%d(\%%rbp)\n", Entry->SinkOffset); break;
|
||||
}
|
||||
|
||||
break;
|
||||
case RET_LONG:
|
||||
case PTR_CHAR:
|
||||
case PTR_INT:
|
||||
case PTR_LONG:
|
||||
case PTR_VOID:
|
||||
case 8:
|
||||
switch(Operation) {
|
||||
case OP_PREINC:
|
||||
fprintf(OutputFile, "\tincq\t%d(\%%rbp)\n", Symbols[ID].SinkOffset); break;
|
||||
fprintf(OutputFile, "\tincq\t%d(\%%rbp)\n", Entry->SinkOffset); break;
|
||||
case OP_PREDEC:
|
||||
fprintf(OutputFile, "\tdecq\t%d(\%%rbp)\n", Symbols[ID].SinkOffset); break;
|
||||
fprintf(OutputFile, "\tdecq\t%d(\%%rbp)\n", Entry->SinkOffset); break;
|
||||
}
|
||||
|
||||
fprintf(OutputFile, "\tmovq\t%d(\%%rbp), %s\n", Symbols[ID].SinkOffset, Registers[Reg]);
|
||||
fprintf(OutputFile, "\tmovq\t%d(\%%rbp), %s\n", Entry->SinkOffset, Registers[Reg]);
|
||||
|
||||
switch(Operation) {
|
||||
case OP_POSTINC:
|
||||
fprintf(OutputFile, "\tincq\t%d(\%%rbp)\n", Symbols[ID].SinkOffset); break;
|
||||
fprintf(OutputFile, "\tincq\t%d(\%%rbp)\n", Entry->SinkOffset); break;
|
||||
case OP_POSTDEC:
|
||||
fprintf(OutputFile, "\tdecq\t%d(\%%rbp)\n", Symbols[ID].SinkOffset); break;
|
||||
fprintf(OutputFile, "\tdecq\t%d(\%%rbp)\n", Entry->SinkOffset); break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
DieMessage("Bad type for loading", TypeNames[Symbols[ID].Type]);
|
||||
DieMessage("Bad type for loading", TypeNames(Entry->Type));
|
||||
}
|
||||
|
||||
return Reg;
|
||||
}
|
||||
|
||||
int AsStrLocalVar(int Register, int ID) {
|
||||
printf("\tStoring contents of %s into %s, type %d, locally\n", Registers[Register], Symbols[ID].Name, Symbols[ID].Type);
|
||||
int AsStrLocalVar(struct SymbolTableEntry* Entry, int Register) {
|
||||
printf("\tStoring contents of %s into %s, type %d, locally\n", Registers[Register], Entry->Name, Entry->Type);
|
||||
|
||||
switch(Symbols[ID].Type) {
|
||||
case RET_CHAR:
|
||||
int TypeSize = PrimitiveSize(Entry->Type);
|
||||
switch(TypeSize) {
|
||||
case 1:
|
||||
// movzbq zeroes, then moves a byte into the quad register
|
||||
fprintf(OutputFile, "\tmovb\t%s, %d(\%%rbp)\n", ByteRegisters[Register], Symbols[ID].SinkOffset);
|
||||
fprintf(OutputFile, "\tmovb\t%s, %d(\%%rbp)\n", ByteRegisters[Register], Entry->SinkOffset);
|
||||
break;
|
||||
|
||||
case RET_INT:
|
||||
fprintf(OutputFile, "\tmovl\t%s, %d(\%%rbp)\n", DoubleRegisters[Register], Symbols[ID].SinkOffset);
|
||||
case 4:
|
||||
fprintf(OutputFile, "\tmovl\t%s, %d(\%%rbp)\n", DoubleRegisters[Register], Entry->SinkOffset);
|
||||
break;
|
||||
|
||||
case RET_LONG:
|
||||
case PTR_CHAR:
|
||||
case PTR_INT:
|
||||
case PTR_LONG:
|
||||
case PTR_VOID:
|
||||
fprintf(OutputFile, "\tmovq\t%s, %d(%%rbp)\n", Registers[Register], Symbols[ID].SinkOffset);
|
||||
case 8:
|
||||
fprintf(OutputFile, "\tmovq\t%s, %d(%%rbp)\n", Registers[Register], Entry->SinkOffset);
|
||||
break;
|
||||
|
||||
default:
|
||||
DieMessage("Bad type for saving", TypeNames[Symbols[ID].Type]);
|
||||
DieMessage("Bad type for saving", TypeNames(Entry->Type));
|
||||
}
|
||||
|
||||
return Register;
|
||||
}
|
||||
|
||||
int AsAddr(int ID) {
|
||||
int AsAddr(struct SymbolTableEntry* Entry) {
|
||||
int Register = RetrieveRegister();
|
||||
printf("\tSaving pointer of %s into %s\n", Symbols[ID].Name, Registers[Register]);
|
||||
printf("\tSaving pointer of %s into %s\n", Entry->Name, Registers[Register]);
|
||||
|
||||
fprintf(OutputFile, "\tleaq\t%s(%%rip), %s\n", Symbols[ID].Name, Registers[Register]);
|
||||
fprintf(OutputFile, "\tleaq\t%s(%%rip), %s\n", Entry->Name, Registers[Register]);
|
||||
return Register;
|
||||
}
|
||||
|
||||
int AsDeref(int Reg, int Type) {
|
||||
|
||||
int DestSize = PrimitiveSize(ValueAt(Type));
|
||||
|
||||
printf("\tDereferencing %s\n", Registers[Reg]);
|
||||
switch(Type) {
|
||||
case PTR_CHAR:
|
||||
switch(DestSize) {
|
||||
case 1:
|
||||
fprintf(OutputFile, "\tmovzbq\t(%s), %s\n", Registers[Reg], Registers[Reg]);
|
||||
break;
|
||||
case PTR_INT:
|
||||
case PTR_LONG:
|
||||
case 2:
|
||||
fprintf(OutputFile, "\tmovslq\t(%s), %s\n", Registers[Reg], Registers[Reg]);
|
||||
case 4:
|
||||
case 8:
|
||||
fprintf(OutputFile, "\tmovq\t(%s), %s\n", Registers[Reg], Registers[Reg]);
|
||||
break;
|
||||
default:
|
||||
|
@ -719,22 +711,22 @@ int AsStrDeref(int Register1, int Register2, int Type) {
|
|||
return Register1;
|
||||
}
|
||||
|
||||
void AsGlobalSymbol(int ID) {
|
||||
void AsGlobalSymbol(struct SymbolTableEntry* Entry) {
|
||||
int TypeSize;
|
||||
|
||||
TypeSize = PrimitiveSize(Symbols[ID].Type);
|
||||
TypeSize = PrimitiveSize(Entry->Type);
|
||||
|
||||
fprintf(OutputFile, "\t.data\n"
|
||||
"\t.globl\t%s\n",
|
||||
Symbols[ID].Name);
|
||||
Entry->Name);
|
||||
|
||||
fprintf(OutputFile, "%s:\n", Symbols[ID].Name);
|
||||
fprintf(OutputFile, "%s:\n", Entry->Name);
|
||||
|
||||
for(int i = 0; i < Symbols[ID].Length; i++) {
|
||||
for(int i = 0; i < Entry->Length; i++) {
|
||||
switch(TypeSize) {
|
||||
case 1: fprintf(OutputFile, "\t.byte\t0\r\n", Symbols[ID].Name); break;
|
||||
case 4: fprintf(OutputFile, "\t.long\t0\r\n", Symbols[ID].Name); break;
|
||||
case 8: fprintf(OutputFile, "\t.quad\t0\r\n", Symbols[ID].Name); break;
|
||||
case 1: fprintf(OutputFile, "\t.byte\t0\r\n", Entry->Name); break;
|
||||
case 4: fprintf(OutputFile, "\t.long\t0\r\n", Entry->Name); break;
|
||||
case 8: fprintf(OutputFile, "\t.quad\t0\r\n", Entry->Name); break;
|
||||
default: DieDecimal("Unknown type in AsNewSymbol", TypeSize); break;
|
||||
}
|
||||
}
|
||||
|
@ -746,13 +738,13 @@ int AsCallWrapper(struct ASTNode* Node) {
|
|||
|
||||
while(CompositeTree) {
|
||||
Register = AssembleTree(CompositeTree->Right, -1, CompositeTree->Operation);
|
||||
AsCopyArgs(Register, CompositeTree->Value.Size);
|
||||
if(Args == 0) Args = CompositeTree->Value.Size;
|
||||
AsCopyArgs(Register, CompositeTree->Size);
|
||||
if(Args == 0) Args = CompositeTree->Size;
|
||||
DeallocateAllRegisters();
|
||||
CompositeTree = CompositeTree->Left;
|
||||
}
|
||||
|
||||
return AsCall(Node->Value.ID, Args);
|
||||
return AsCall(Node->Symbol, Args);
|
||||
}
|
||||
|
||||
void AsCopyArgs(int Register, int Position) {
|
||||
|
@ -763,14 +755,14 @@ void AsCopyArgs(int Register, int Position) {
|
|||
}
|
||||
}
|
||||
|
||||
int AsCall(int FuncID, int Args) {
|
||||
int AsCall(struct SymbolTableEntry* Entry, int Args) {
|
||||
|
||||
int OutRegister = RetrieveRegister();
|
||||
|
||||
printf("\t\tCalling function %s with %d parameters\n", Symbols[FuncID].Name, Args);
|
||||
printf("\t\tCalling function %s with %d parameters\n", Entry->Name, Args);
|
||||
printf("\t\t\tFunction returns into %s\n", Registers[OutRegister]);
|
||||
|
||||
fprintf(OutputFile, "\tcall\t%s\n", Symbols[FuncID].Name);
|
||||
fprintf(OutputFile, "\tcall\t%s\n", Entry->Name);
|
||||
if(Args > 4)
|
||||
fprintf(OutputFile, "\taddq\t$%d, %%rsp\n", 8 * (Args - 4));
|
||||
|
||||
|
@ -779,11 +771,11 @@ int AsCall(int FuncID, int Args) {
|
|||
return OutRegister;
|
||||
}
|
||||
|
||||
int AsReturn(int Register, int FuncID) {
|
||||
int AsReturn(struct SymbolTableEntry* Entry, int Register) {
|
||||
|
||||
printf("\t\tCreating return for function %s\n", Symbols[FuncID].Name);
|
||||
printf("\t\tCreating return for function %s\n", Entry->Name);
|
||||
|
||||
switch(Symbols[FuncID].Type) {
|
||||
switch(Entry->Type) {
|
||||
case RET_CHAR:
|
||||
fprintf(OutputFile, "\tmovzbl\t%s, %%eax\n", ByteRegisters[Register]);
|
||||
break;
|
||||
|
@ -797,11 +789,11 @@ int AsReturn(int Register, int FuncID) {
|
|||
break;
|
||||
|
||||
default:
|
||||
DieMessage("Bad function type in generating return", TypeNames[Symbols[FuncID].Type]);
|
||||
DieMessage("Bad function type in generating return", TypeNames(Entry->Type));
|
||||
|
||||
}
|
||||
|
||||
AsJmp(Symbols[FuncID].EndLabel);
|
||||
AsJmp(Entry->EndLabel);
|
||||
|
||||
}
|
||||
|
||||
|
@ -920,9 +912,10 @@ void AssemblerPreamble() {
|
|||
OutputFile);
|
||||
}
|
||||
|
||||
void AsFunctionPreamble(int FunctionID) {
|
||||
char* Name = Symbols[FunctionID].Name;
|
||||
int ParamOffset = 0, ParamReg = 9;
|
||||
void AsFunctionPreamble(struct SymbolTableEntry* Entry) {
|
||||
char* Name = Entry->Name;
|
||||
struct SymbolTableEntry* Param, *Local;
|
||||
int ParamOffset = 0, ParamReg = 9, ParamCount = 0;
|
||||
|
||||
LocalVarOffset = 4; // Prepare parameters
|
||||
|
||||
|
@ -943,24 +936,19 @@ void AsFunctionPreamble(int FunctionID) {
|
|||
int LoopIndex;
|
||||
|
||||
// If we have parameters, move them to the last 4 registers
|
||||
for(LoopIndex = SYMBOLS - 1; LoopIndex > CurrentLocal; LoopIndex--) {
|
||||
if(Symbols[LoopIndex].Storage != SC_PARAM)
|
||||
break;
|
||||
if(LoopIndex < SYMBOLS - 4) // We only have 4 argument registers
|
||||
break;
|
||||
for(Param = Entry->Start, ParamCount = 1; Param != NULL; Param = Param->NextSymbol, ParamCount++) {
|
||||
if(ParamCount > 4) { // We only have 4 argument registers
|
||||
Param->SinkOffset = ParamOffset;
|
||||
ParamOffset += 8;
|
||||
}
|
||||
|
||||
Symbols[LoopIndex].SinkOffset = AsCalcOffset(Symbols[LoopIndex].Type);
|
||||
AsStrLocalVar(ParamReg--, LoopIndex);
|
||||
Entry->SinkOffset = AsCalcOffset(Param->Type);
|
||||
AsStrLocalVar(Param, ParamReg--);
|
||||
}
|
||||
|
||||
// If we have more parameters, move them to the stack
|
||||
for(; LoopIndex > CurrentLocal; LoopIndex--) {
|
||||
if(Symbols[LoopIndex].Storage == SC_PARAM) {
|
||||
Symbols[LoopIndex].SinkOffset = ParamOffset + 16;
|
||||
ParamOffset += 8;
|
||||
} else {
|
||||
Symbols[LoopIndex].SinkOffset = AsCalcOffset(Symbols[LoopIndex].Type);
|
||||
}
|
||||
for(Local = Locals; Local != NULL; Local = Local->NextSymbol) {
|
||||
Local->SinkOffset = AsCalcOffset(Local->Type);
|
||||
}
|
||||
|
||||
// With all the parameters on the stack, we can allocate the shadow space
|
||||
|
@ -970,8 +958,8 @@ void AsFunctionPreamble(int FunctionID) {
|
|||
|
||||
}
|
||||
|
||||
void AsFunctionEpilogue(int FunctionID) {
|
||||
AsLabel(Symbols[FunctionID].EndLabel);
|
||||
void AsFunctionEpilogue(struct SymbolTableEntry* Entry) {
|
||||
AsLabel(Entry->EndLabel);
|
||||
|
||||
fprintf(OutputFile,
|
||||
"\tpopq\t%%rbp\n"
|
||||
|
|
52
src/Dump.c
52
src/Dump.c
|
@ -12,27 +12,27 @@ static int GenerateSrg() {
|
|||
return srgId++;
|
||||
}
|
||||
|
||||
void DumpTree(struct ASTNode* node, int level) {
|
||||
void DumpTree(struct ASTNode* Node, int level) {
|
||||
int Lfalse, Lstart, Lend;
|
||||
|
||||
// Handle weirdo loops and conditions first.
|
||||
switch(node->Operation) {
|
||||
switch(Node->Operation) {
|
||||
case OP_IF:
|
||||
Lfalse = GenerateSrg();
|
||||
for(int i = 0; i < level; i++)
|
||||
fprintf(stdout, " ");
|
||||
fprintf(stdout, "IF");
|
||||
if(node->Right) {
|
||||
if(Node->Right) {
|
||||
Lend = GenerateSrg();
|
||||
fprintf(stdout, ", end label %d", Lend);
|
||||
}
|
||||
|
||||
fprintf(stdout, "\n");
|
||||
DumpTree(node->Left, level + 2);
|
||||
DumpTree(node->Middle, level + 2);
|
||||
DumpTree(Node->Left, level + 2);
|
||||
DumpTree(Node->Middle, level + 2);
|
||||
|
||||
if(node->Right)
|
||||
DumpTree(node->Right, level + 2);
|
||||
if(Node->Right)
|
||||
DumpTree(Node->Right, level + 2);
|
||||
|
||||
return;
|
||||
case OP_LOOP:
|
||||
|
@ -41,28 +41,28 @@ void DumpTree(struct ASTNode* node, int level) {
|
|||
fprintf(stdout, " ");
|
||||
fprintf(stdout, "LOOP starts at %d\n", Lstart);
|
||||
Lend = GenerateSrg();
|
||||
DumpTree(node->Left, level + 2);
|
||||
DumpTree(node->Right, level + 2);
|
||||
DumpTree(Node->Left, level + 2);
|
||||
DumpTree(Node->Right, level + 2);
|
||||
return;
|
||||
}
|
||||
|
||||
// If current node is a compound, we treat it as if we didn't just enter a loop.
|
||||
if(node->Operation == OP_COMP)
|
||||
if(Node->Operation == OP_COMP)
|
||||
level = -2;
|
||||
|
||||
if(node->Left)
|
||||
DumpTree(node->Left, level + 2);
|
||||
if(Node->Left)
|
||||
DumpTree(Node->Left, level + 2);
|
||||
|
||||
if(node->Right)
|
||||
DumpTree(node->Right, level + 2);
|
||||
if(Node->Right)
|
||||
DumpTree(Node->Right, level + 2);
|
||||
|
||||
// The meat of this operation!
|
||||
for(int i = 0; i < level; i++)
|
||||
fprintf(stdout, " ");
|
||||
|
||||
switch (node->Operation){
|
||||
switch (Node->Operation){
|
||||
case OP_COMP: fprintf(stdout, "\n\n"); return;
|
||||
case OP_FUNC: fprintf(stdout, "OP_FUNC %s\n", Symbols[node->Value.ID].Name); return;
|
||||
case OP_FUNC: fprintf(stdout, "OP_FUNC %s\n", Node->Symbol->Name); return;
|
||||
case OP_ADD: fprintf(stdout, "OP_ADD\n"); return;
|
||||
case OP_SUBTRACT: fprintf(stdout, "OP_SUBTRACT\n"); return;
|
||||
case OP_MULTIPLY: fprintf(stdout, "OP_MULTIPLY\n"); return;
|
||||
|
@ -73,22 +73,22 @@ void DumpTree(struct ASTNode* node, int level) {
|
|||
case OP_GREAT: fprintf(stdout, "OP_GREAT\n"); return;
|
||||
case OP_LESSE: fprintf(stdout, "OP_LESSE\n"); return;
|
||||
case OP_GREATE: fprintf(stdout, "OP_GREATE\n"); return;
|
||||
case TERM_INTLITERAL: fprintf(stdout, "TERM_INTLITERAL %d\n", node->Value.IntValue); return;
|
||||
case TERM_STRLITERAL: fprintf(stdout, "TERM_STRLITERAL rval L%d\n", node->Value.IntValue); return;
|
||||
case TERM_INTLITERAL: fprintf(stdout, "TERM_INTLITERAL %d\n", Node->IntValue); return;
|
||||
case TERM_STRLITERAL: fprintf(stdout, "TERM_STRLITERAL rval L%d\n", Node->IntValue); return;
|
||||
case REF_IDENT:
|
||||
if(node->RVal)
|
||||
fprintf(stdout, "REF_IDENT rval %s\n", Symbols[node->Value.ID].Name);
|
||||
if(Node->RVal)
|
||||
fprintf(stdout, "REF_IDENT rval %s\n", Node->Symbol->Name);
|
||||
else
|
||||
fprintf(stdout, "REF_IDENT %s\n", Symbols[node->Value.ID].Name);
|
||||
fprintf(stdout, "REF_IDENT %s\n", Node->Symbol->Name);
|
||||
return;
|
||||
case OP_ASSIGN: fprintf(stdout, "OP_ASSIGN\n"); return;
|
||||
case OP_WIDEN: fprintf(stdout, "OP_WIDEN\n"); return;
|
||||
case OP_RET: fprintf(stdout, "OP_RET\n"); return;
|
||||
case OP_CALL: fprintf(stdout, "OP_CALL %s\n", Symbols[node->Value.ID].Name); return;
|
||||
case OP_ADDRESS: fprintf(stdout, "OP_ADDRESS %s\n", Symbols[node->Value.ID].Name); return;
|
||||
case OP_CALL: fprintf(stdout, "OP_CALL %s\n", Node->Symbol->Name); return;
|
||||
case OP_ADDRESS: fprintf(stdout, "OP_ADDRESS %s\n", Node->Symbol->Name); return;
|
||||
case OP_DEREF:
|
||||
fprintf(stdout, "OP_DEREF %s\n", node->RVal ? "rval" : ""); return;
|
||||
case OP_SCALE: fprintf(stdout, "OP_SCALE %s\n", TypeNames[node->Value.Size]); return;
|
||||
fprintf(stdout, "OP_DEREF %s\n", Node->RVal ? "rval" : ""); return;
|
||||
case OP_SCALE: fprintf(stdout, "OP_SCALE %s\n", TypeNames(Node->Size)); return;
|
||||
|
||||
case OP_BOOLOR: fprintf(stdout, "OP_BOOLOR\n"); return;
|
||||
case OP_BOOLAND: fprintf(stdout, "OP_BOOLAND\n"); return;
|
||||
|
@ -111,7 +111,7 @@ void DumpTree(struct ASTNode* node, int level) {
|
|||
case OP_BOOLCONV: fprintf(stdout, "OP_BOOLCONV\n"); return;
|
||||
|
||||
default:
|
||||
DieDecimal("Unknown Dump Operator", node->Operation);
|
||||
DieDecimal("Unknown Dump Operator", Node->Operation);
|
||||
}
|
||||
|
||||
}
|
|
@ -10,7 +10,7 @@
|
|||
#include <errno.h>
|
||||
|
||||
|
||||
int TypeSizes[9] = { 0, 1, 4, 8, 0, 8, 8, 8, 8}; // in BYTES
|
||||
int TypeSizes[5] = { 0, 1, 4, 8, 0}; // in BYTES
|
||||
|
||||
char* TokenNames[] = {
|
||||
"End of file",
|
||||
|
@ -76,9 +76,6 @@ char* TokenNames[] = {
|
|||
"Return keyword"
|
||||
};
|
||||
|
||||
char* TypeNames[9] = { "none", "char", "int", "long", "void", "charptr", "intptr", "longptr", "voidptr"};
|
||||
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
/* Line = 1;
|
||||
Overread = '\n';
|
||||
|
|
43
src/Parser.c
43
src/Parser.c
|
@ -52,33 +52,35 @@ struct ASTNode* ConstructASTNode(int Operation, int Type,
|
|||
struct ASTNode* Left,
|
||||
struct ASTNode* Middle,
|
||||
struct ASTNode* Right,
|
||||
struct SymbolTableEntry* Symbol,
|
||||
int IntValue) {
|
||||
|
||||
struct ASTNode* Node;
|
||||
|
||||
Node = (struct ASTNode*) malloc(sizeof(struct ASTNode));
|
||||
|
||||
if(!Node) {
|
||||
fprintf(stderr, "Unable to allocate node!");
|
||||
exit(1);
|
||||
}
|
||||
if(!Node)
|
||||
Die("Unable to allocate node!");
|
||||
|
||||
|
||||
Node->Operation = Operation;
|
||||
Node->ExprType = Type;
|
||||
Node->Left = Left;
|
||||
Node->Middle = Middle;
|
||||
Node->Right = Right;
|
||||
Node->Value.IntValue = IntValue;
|
||||
Node->Symbol = Symbol;
|
||||
Node->IntValue = IntValue;
|
||||
|
||||
return Node;
|
||||
}
|
||||
|
||||
|
||||
struct ASTNode* ConstructASTLeaf(int Operation, int Type, int IntValue) {
|
||||
return ConstructASTNode(Operation, Type, NULL, NULL, NULL, IntValue);
|
||||
struct ASTNode* ConstructASTLeaf(int Operation, int Type, struct SymbolTableEntry* Symbol, int IntValue) {
|
||||
return ConstructASTNode(Operation, Type, NULL, NULL, NULL, Symbol, IntValue);
|
||||
}
|
||||
|
||||
struct ASTNode* ConstructASTBranch(int Operation, int Type, struct ASTNode* Left, int IntValue) {
|
||||
return ConstructASTNode(Operation, Type, Left, NULL, NULL, IntValue);
|
||||
struct ASTNode* ConstructASTBranch(int Operation, int Type, struct ASTNode* Left, struct SymbolTableEntry* Symbol, int IntValue) {
|
||||
return ConstructASTNode(Operation, Type, Left, NULL, NULL, Symbol, IntValue);
|
||||
}
|
||||
|
||||
|
||||
|
@ -116,15 +118,15 @@ struct ASTNode* ParsePrimary(void) {
|
|||
case LI_INT:
|
||||
|
||||
if((CurrentToken.value >= 0) && (CurrentToken.value < 256))
|
||||
Node = ConstructASTLeaf(TERM_INTLITERAL, RET_CHAR, CurrentToken.value);
|
||||
Node = ConstructASTLeaf(TERM_INTLITERAL, RET_CHAR, NULL, CurrentToken.value);
|
||||
else
|
||||
Node = ConstructASTLeaf(TERM_INTLITERAL, RET_INT, CurrentToken.value);
|
||||
Node = ConstructASTLeaf(TERM_INTLITERAL, RET_INT, NULL, CurrentToken.value);
|
||||
break;
|
||||
|
||||
case LI_STR:
|
||||
|
||||
ID = AsNewString(CurrentIdentifier);
|
||||
Node = ConstructASTLeaf(TERM_STRLITERAL, PTR_CHAR, ID);
|
||||
Node = ConstructASTLeaf(TERM_STRLITERAL, PointerTo(RET_CHAR), NULL, ID);
|
||||
break;
|
||||
|
||||
case TY_IDENTIFIER:
|
||||
|
@ -196,8 +198,7 @@ struct ASTNode* ParsePrecedenceASTNode(int PreviousTokenPrecedence) {
|
|||
//printf("\tAssigning variable: %s value %d\n", Symbols[FindSymbol(CurrentIdentifier)].Name, RightNode->Value.IntValue);
|
||||
|
||||
// LeftNode holds the target, the target variable in this case
|
||||
printf("\t\tAssigning variable: %s\n", Symbols[LeftNode->Value.ID].Name);
|
||||
printf("\t\tAfter parsing, the identifier name is %s, id %d in the symbol table.\n", Symbols[LeftNode->Value.ID].Name, LeftNode->Value.ID);
|
||||
printf("\t\tAssigning variable: %s\n", LeftNode->Symbol->Name);
|
||||
|
||||
LeftTemp = LeftNode;
|
||||
LeftNode = RightNode;
|
||||
|
@ -253,7 +254,7 @@ struct ASTNode* ParsePrecedenceASTNode(int PreviousTokenPrecedence) {
|
|||
if(RightTemp != NULL)
|
||||
RightNode = RightTemp; // ConstructASTBranch(RightType, LeftNode->ExprType, RightNode, 0);
|
||||
|
||||
LeftNode = ConstructASTNode(ParseTokenToOperation(NodeType), LeftNode->ExprType, LeftNode, NULL, RightNode, 0);
|
||||
LeftNode = ConstructASTNode(ParseTokenToOperation(NodeType), LeftNode->ExprType, LeftNode, NULL, RightNode, NULL, 0);
|
||||
NodeType = CurrentToken.type;
|
||||
if(NodeType == LI_SEMIC || NodeType == LI_RPARE || NodeType == LI_RBRAS) {
|
||||
LeftNode->RVal = 1;
|
||||
|
@ -367,17 +368,17 @@ int ParseAST(struct ASTNode* Node) {
|
|||
|
||||
struct ASTNode* CallFunction() {
|
||||
struct ASTNode* Tree;
|
||||
int FuncID;
|
||||
struct SymbolTableEntry* Function;
|
||||
|
||||
//TODO: Test structural type!
|
||||
if((FuncID = FindSymbol(CurrentIdentifier)) == -1 && (Symbols[FuncID].Structure == ST_FUNC))
|
||||
if((Function = FindSymbol(CurrentIdentifier)) == NULL || (Function->Structure != ST_FUNC))
|
||||
DieMessage("Undeclared function", CurrentIdentifier);
|
||||
|
||||
VerifyToken(LI_LPARE, "(");
|
||||
|
||||
Tree = GetExpressionList();
|
||||
|
||||
Tree = ConstructASTBranch(OP_CALL, Symbols[FuncID].Type, Tree, FuncID);
|
||||
Tree = ConstructASTBranch(OP_CALL, Function->Type, Tree, Function, 0);
|
||||
|
||||
VerifyToken(LI_RPARE, ")");
|
||||
|
||||
|
@ -392,7 +393,7 @@ struct ASTNode* GetExpressionList() {
|
|||
Child = ParsePrecedenceASTNode(0);
|
||||
Count++;
|
||||
|
||||
Tree = ConstructASTNode(OP_COMP, PTR_VOID, Tree, NULL, Child, Count);
|
||||
Tree = ConstructASTNode(OP_COMP, PointerTo(RET_VOID), Tree, NULL, Child, NULL, Count);
|
||||
|
||||
switch(CurrentToken.type) {
|
||||
case LI_COM:
|
||||
|
@ -475,7 +476,7 @@ struct ASTNode* ParseCompound() {
|
|||
if(Left == NULL)
|
||||
Left = Tree;
|
||||
else
|
||||
Left = ConstructASTNode(OP_COMP, RET_NONE, Left, NULL, Tree, 0);
|
||||
Left = ConstructASTNode(OP_COMP, RET_NONE, Left, NULL, Tree, NULL, 0);
|
||||
}
|
||||
|
||||
if(CurrentToken.type == LI_RBRAC) {
|
||||
|
@ -507,7 +508,7 @@ void ParseGlobals() {
|
|||
printf("\tParsing function");
|
||||
Tree = ParseFunction(Type);
|
||||
if(Tree) {
|
||||
printf("\nBeginning assembler creation of new function %s\n", Symbols[Tree->Value.ID].Name);
|
||||
printf("\nBeginning assembler creation of new function %s\n", Tree->Symbol->Name);
|
||||
AssembleTree(Tree, -1, 0);
|
||||
FreeLocals();
|
||||
} else {
|
||||
|
|
|
@ -8,45 +8,39 @@
|
|||
#include <Data.h>
|
||||
|
||||
int PointerTo(int Type) {
|
||||
//Type = Type + 1;
|
||||
printf("\t\tPointerising a %s\n", TypeNames[Type]);
|
||||
// As it stands, the conversion between
|
||||
// RET and PTR is +4.
|
||||
// TODO: if we add types, increase this number
|
||||
// TODO: Make this a proper translation table
|
||||
// TODO: More checks! This can go wrong easily!
|
||||
if(Type >= RET_CHAR && Type <= RET_VOID) {
|
||||
return Type + (PTR_CHAR - RET_CHAR);
|
||||
} else {
|
||||
DieDecimal("Unable to create a pointer to the desired type", Type);
|
||||
}
|
||||
|
||||
return -1;
|
||||
if((Type & 0xf) == 0xf)
|
||||
DieDecimal("Unrecognized type in pointerisation", Type);
|
||||
printf("\t\tPointerising a %s\n", TypeNames(Type));
|
||||
return (Type + 1);
|
||||
}
|
||||
|
||||
int ValueAt(int Type) {
|
||||
|
||||
printf("\t\tDereferencing a %s\n", TypeNames[Type]);
|
||||
printf("\t\tDereferencing a %s\n", TypeNames(Type));
|
||||
//TODO: this is still bullshittery!
|
||||
if(Type >= PTR_CHAR && Type <= PTR_VOID) {
|
||||
printf("\t\t\tDereference of %s is %s.\r\n", TypeNames[Type], TypeNames[Type - 4]);
|
||||
return Type - 4;
|
||||
} else {
|
||||
DieDecimal("Unable to dereference type", Type);
|
||||
}
|
||||
return -1;
|
||||
if((Type & 0xf) == 0x0)
|
||||
DieDecimal("Unrecognized type in defererencing", Type);
|
||||
return (Type - 1);
|
||||
}
|
||||
|
||||
int ParseOptionalPointer() {
|
||||
|
||||
int Type;
|
||||
// TODO: THIS IS WRONG AND SHOULD NOT EXIST
|
||||
|
||||
if(CurrentToken.type >= TY_CHAR && CurrentToken.type <= TY_VOID) {
|
||||
Type = CurrentToken.type - (TY_CHAR - RET_CHAR);
|
||||
printf("\t\tConverting a %s token to a %s type.\n", TokenNames[CurrentToken.type], TypeNames[Type]);
|
||||
} else {
|
||||
DieDecimal("Illegal type for pointerisation", CurrentToken.type);
|
||||
|
||||
switch(CurrentToken.type) {
|
||||
case TY_VOID:
|
||||
Type = RET_VOID;
|
||||
break;
|
||||
case TY_CHAR:
|
||||
Type = RET_CHAR;
|
||||
break;
|
||||
case TY_INT:
|
||||
Type = RET_INT;
|
||||
break;
|
||||
case TY_LONG:
|
||||
Type = RET_LONG;
|
||||
break;
|
||||
default:
|
||||
DieDecimal("Illegal type for pointerisation", CurrentToken.type);
|
||||
}
|
||||
// Recursively scan more *s
|
||||
// This makes things like:
|
||||
|
@ -66,13 +60,13 @@ int ParseOptionalPointer() {
|
|||
|
||||
struct ASTNode* AccessArray() {
|
||||
struct ASTNode* LeftNode, *RightNode;
|
||||
int ID;
|
||||
struct SymbolTableEntry* Entry;
|
||||
|
||||
printf("\tAccessing array %s as requested\r\n", CurrentIdentifier);
|
||||
if ((ID = FindSymbol(CurrentIdentifier)) == -1 || Symbols[ID].Structure != ST_ARR)
|
||||
if ((Entry = FindSymbol(CurrentIdentifier)) == NULL || Entry->Structure != ST_ARR)
|
||||
DieMessage("Accessing undeclared array", CurrentIdentifier);
|
||||
|
||||
LeftNode = ConstructASTLeaf(OP_ADDRESS, Symbols[ID].Type, ID);
|
||||
LeftNode = ConstructASTLeaf(OP_ADDRESS, Entry->Type, Entry, 0);
|
||||
//printf("\t\tCurrent token: %s\r\n", TokenNames[CurrentToken.type]);
|
||||
Tokenise(&CurrentToken);
|
||||
//printf("\t\tCurrent token: %s\r\n", TokenNames[CurrentToken.type]);
|
||||
|
@ -84,12 +78,12 @@ struct ASTNode* AccessArray() {
|
|||
if(!TypeIsInt(RightNode->ExprType))
|
||||
Die("Array index is not integer");
|
||||
|
||||
printf("\t\tPreparing types - RightNode of type %s must be mutated to LeftNode type %s\r\n", TypeNames[RightNode->ExprType], TypeNames[LeftNode->ExprType]);
|
||||
printf("\t\tPreparing types - RightNode of type %s must be mutated to LeftNode type %s\r\n", (RightNode->ExprType), TypeNames(LeftNode->ExprType));
|
||||
RightNode = MutateType(RightNode, LeftNode->ExprType, OP_ADD);
|
||||
|
||||
LeftNode = ConstructASTNode(OP_ADD, Symbols[ID].Type, LeftNode, NULL, RightNode, 0);
|
||||
LeftNode = ConstructASTNode(OP_ADD, Entry->Type, LeftNode, NULL, RightNode, NULL, 0);
|
||||
printf("\tAccessArray: Preparing LeftNode for dereference.\r\n");
|
||||
LeftNode = ConstructASTBranch(OP_DEREF, ValueAt(LeftNode->ExprType), LeftNode, 0);
|
||||
LeftNode = ConstructASTBranch(OP_DEREF, ValueAt(LeftNode->ExprType), LeftNode, NULL, 0);
|
||||
printf("\tArray Access constructed\r\n");
|
||||
return LeftNode;
|
||||
}
|
154
src/Statements.c
154
src/Statements.c
|
@ -8,21 +8,21 @@
|
|||
#include <Data.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
static int ReadParameters(int FuncID) {
|
||||
int TokenType, ParamCount = 0, ProtoParamCount, ParamIndex;
|
||||
ParamIndex = FuncID + 1;
|
||||
if(ParamIndex) // If FuncID > -1 (If the function exists)
|
||||
ProtoParamCount = Symbols[FuncID].Length; // Set the prototype length
|
||||
static int ReadParameters(struct SymbolTableEntry* FunctionSymbol) {
|
||||
int TokenType, ParamCount = 0;
|
||||
struct SymbolTableEntry* PrototypePointer = NULL;
|
||||
|
||||
if(FunctionSymbol != NULL)
|
||||
PrototypePointer = FunctionSymbol->Start;
|
||||
|
||||
while(CurrentToken.type != LI_RPARE) {
|
||||
TokenType = ParseOptionalPointer();
|
||||
VerifyToken(TY_IDENTIFIER, "identifier");
|
||||
|
||||
if(ParamIndex) {
|
||||
if(TokenType != Symbols[FuncID].Type)
|
||||
if(PrototypePointer != NULL) {
|
||||
if(TokenType != PrototypePointer->Type)
|
||||
DieDecimal("Function paramater of invalid type at index", ParamCount + 1);
|
||||
ParamIndex++;
|
||||
PrototypePointer=PrototypePointer->NextSymbol;
|
||||
} else {
|
||||
BeginVariableDeclaration(TokenType, SC_PARAM);
|
||||
}
|
||||
|
@ -39,8 +39,8 @@ static int ReadParameters(int FuncID) {
|
|||
}
|
||||
}
|
||||
|
||||
if((FuncID != -1) && (ParamCount != ProtoParamCount))
|
||||
DieMessage("Invalid number of parameters in prototyped function", Symbols[FuncID].Name);
|
||||
if((FunctionSymbol != NULL) && (ParamCount != FunctionSymbol->Length))
|
||||
DieMessage("Invalid number of parameters in prototyped function", FunctionSymbol->Name);
|
||||
|
||||
return ParamCount;
|
||||
}
|
||||
|
@ -49,77 +49,86 @@ static int ReadParameters(int FuncID) {
|
|||
* Handles the declaration of a type of a variable.
|
||||
* int newVar;
|
||||
*
|
||||
* It verifies that we have the `int` keyword followed by a
|
||||
* It verifies that we have a type keyword followed by a
|
||||
* unique, non-keyword identifier.
|
||||
*
|
||||
* It then stores this variable into the symbol table.
|
||||
*
|
||||
* //TODO: Assemble this into the symbol table.
|
||||
* //TODO: int i = 5;
|
||||
* It then stores this variable into the symbol table,
|
||||
* and returns the new item.
|
||||
*
|
||||
*/
|
||||
void BeginVariableDeclaration(int Type, int Scope) {
|
||||
int ID;
|
||||
printf("type: %s\n", TypeNames[Type]);
|
||||
struct SymbolTableEntry* BeginVariableDeclaration(int Type, int Scope) {
|
||||
struct SymbolTableEntry* Symbol = NULL;
|
||||
|
||||
switch(Scope) {
|
||||
case SC_GLOBAL:
|
||||
if(FindGlobal(CurrentIdentifier) != NULL)
|
||||
DieMessage("Invalid redeclaration of global variable", CurrentIdentifier);
|
||||
case SC_LOCAL:
|
||||
case SC_PARAM:
|
||||
if(FindLocal(CurrentIdentifier) != NULL)
|
||||
DieMessage("Invalid redelcaration of local variable", CurrentIdentifier);
|
||||
}
|
||||
|
||||
if(CurrentToken.type == LI_LBRAS) {
|
||||
Tokenise(&CurrentToken);
|
||||
//Type = Type - 2;
|
||||
|
||||
if(CurrentToken.type == LI_INT) {
|
||||
printf("Adding array %s that is %d x %s.\r\n", CurrentIdentifier, CurrentToken.value, TypeNames[Type]);
|
||||
if(Scope == SC_LOCAL)
|
||||
Die("Local arrays are not supported");
|
||||
else
|
||||
AddSymbol(CurrentIdentifier, PointerTo(Type), ST_ARR, Scope, 0, CurrentToken.value);
|
||||
switch(Scope) {
|
||||
case SC_GLOBAL:
|
||||
Symbol = AddSymbol(CurrentIdentifier, PointerTo(Type), ST_ARR, Scope, 1, 0);
|
||||
break;
|
||||
case SC_LOCAL:
|
||||
case SC_PARAM:
|
||||
Die("Local arrays are unimplemented");
|
||||
}
|
||||
}
|
||||
|
||||
Tokenise(&CurrentToken);
|
||||
VerifyToken(LI_RBRAS, "]");
|
||||
} else {
|
||||
printf("Adding var %s that is a %s\r\n", CurrentIdentifier, TypeNames[Type]);
|
||||
if(Scope == SC_LOCAL) {
|
||||
if(AddSymbol(CurrentIdentifier, Type, ST_VAR, Scope, 0, 1) == -1)
|
||||
Die("Illegal state: Identical locals in current function");
|
||||
} else {
|
||||
AddSymbol(CurrentIdentifier, Type, ST_VAR, Scope, 0, 1);
|
||||
}
|
||||
Symbol = AddSymbol(CurrentIdentifier, Type, ST_VAR, Scope, 1, 0);
|
||||
}
|
||||
|
||||
//VerifyToken(LI_SEMIC, ";");
|
||||
return Symbol;
|
||||
|
||||
}
|
||||
|
||||
struct ASTNode* ParseFunction(int Type) {
|
||||
struct ASTNode* Tree;
|
||||
struct ASTNode* FinalStatement;
|
||||
struct SymbolTableEntry* OldFunction, *NewFunction = NULL;
|
||||
int SymbolSlot, BreakLabel, ParamCount, ID;
|
||||
|
||||
if((ID = FindSymbol(CurrentIdentifier)) != -1)
|
||||
if(Symbols[ID].Structure != ST_FUNC)
|
||||
ID = -1;
|
||||
|
||||
printf("\nIdentified%sfunction %s of return type %s, end label %d\n", (ID == -1) ? " new " : " overloaded ", CurrentIdentifier, TypeNames[Type], BreakLabel);
|
||||
|
||||
if(ID == -1) {
|
||||
SymbolSlot = AddSymbol(CurrentIdentifier, Type, ST_FUNC, SC_GLOBAL, BreakLabel, 1);
|
||||
CurrentFunction = SymbolSlot;
|
||||
if((OldFunction = FindSymbol(CurrentIdentifier)) != NULL)
|
||||
if(OldFunction->Storage != ST_FUNC)
|
||||
OldFunction = NULL;
|
||||
if(OldFunction == NULL) {
|
||||
BreakLabel = NewLabel();
|
||||
NewFunction = AddSymbol(CurrentIdentifier, Type, ST_FUNC, SC_GLOBAL, BreakLabel, 0);
|
||||
}
|
||||
|
||||
VerifyToken(LI_LPARE, "(");
|
||||
ParamCount = ReadParameters(ID);
|
||||
ParamCount = ReadParameters(OldFunction);
|
||||
VerifyToken(LI_RPARE, ")");
|
||||
|
||||
if(ID == -1) {
|
||||
Symbols[SymbolSlot].Length = ParamCount;
|
||||
ID = SymbolSlot;
|
||||
if(NewFunction) {
|
||||
NewFunction->Elements = ParamCount;
|
||||
NewFunction->Start = Params;
|
||||
OldFunction = NewFunction;
|
||||
}
|
||||
|
||||
Params = ParamsEnd = NULL;
|
||||
|
||||
if(CurrentToken.type == LI_SEMIC) {
|
||||
Tokenise(&CurrentToken);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
printf("\nIdentified%sfunction %s of return type %s, end label %d\n", (OldFunction == NULL) ? " new " : " overloaded ", OldFunction->Name, TypeNames(Type), BreakLabel);
|
||||
|
||||
|
||||
FunctionEntry = OldFunction;
|
||||
|
||||
Tree = ParseCompound();
|
||||
|
||||
if(Type != RET_VOID) {
|
||||
|
@ -132,7 +141,7 @@ struct ASTNode* ParseFunction(int Type) {
|
|||
|
||||
}
|
||||
|
||||
return ConstructASTBranch(OP_FUNC, Tree->ExprType, Tree, SymbolSlot);
|
||||
return ConstructASTBranch(OP_FUNC, Tree->ExprType, Tree, OldFunction, BreakLabel);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -145,10 +154,10 @@ struct ASTNode* ParseFunction(int Type) {
|
|||
|
||||
struct ASTNode* ReturnStatement() {
|
||||
struct ASTNode* Tree;
|
||||
int ReturnType, FunctionType;
|
||||
int ReturnType;
|
||||
|
||||
|
||||
if(Symbols[CurrentFunction].Type == RET_VOID)
|
||||
if(FunctionEntry->Type == RET_VOID)
|
||||
Die("Attempt to return from void function");
|
||||
|
||||
VerifyToken(KW_RETURN, "return");
|
||||
|
@ -162,7 +171,7 @@ struct ASTNode* ReturnStatement() {
|
|||
FunctionType = Symbols[CurrentFunction].Type;
|
||||
*/
|
||||
|
||||
Tree = MutateType(Tree, Symbols[CurrentFunction].Type, 0);
|
||||
Tree = MutateType(Tree, FunctionEntry->Type, 0);
|
||||
if(Tree == NULL)
|
||||
Die("Returning a value of incorrect type for function");
|
||||
|
||||
|
@ -171,9 +180,9 @@ struct ASTNode* ReturnStatement() {
|
|||
Tree = ConstructASTBranch(ReturnType, FunctionType, Tree, 0);
|
||||
*/
|
||||
|
||||
Tree = ConstructASTBranch(OP_RET, RET_NONE, Tree, 0);
|
||||
Tree = ConstructASTBranch(OP_RET, RET_NONE, Tree, FunctionEntry, 0);
|
||||
|
||||
printf("\t\tReturning from function %s\n", Symbols[CurrentFunction].Name);
|
||||
printf("\t\tReturning from function %s\n", FunctionEntry->Name);
|
||||
|
||||
VerifyToken(LI_RPARE, ")"); // TODO: OPTIONALISE!
|
||||
|
||||
|
@ -245,7 +254,7 @@ struct ASTNode* IfStatement() {
|
|||
// No null checking, no arithmetic, no functions.
|
||||
// TODO: this
|
||||
if(Condition->Operation < OP_EQUAL || Condition->Operation > OP_GREATE)
|
||||
Condition = ConstructASTBranch(OP_BOOLCONV, Condition->ExprType, Condition, 0);
|
||||
Condition = ConstructASTBranch(OP_BOOLCONV, Condition->ExprType, Condition, NULL, 0);
|
||||
|
||||
VerifyToken(LI_RPARE, ")");
|
||||
|
||||
|
@ -256,7 +265,7 @@ struct ASTNode* IfStatement() {
|
|||
False = ParseCompound();
|
||||
}
|
||||
|
||||
return ConstructASTNode(OP_IF, RET_NONE, Condition, True, False, 0);
|
||||
return ConstructASTNode(OP_IF, RET_NONE, Condition, True, False, NULL, 0);
|
||||
}
|
||||
|
||||
struct ASTNode* WhileStatement() {
|
||||
|
@ -269,13 +278,13 @@ struct ASTNode* WhileStatement() {
|
|||
|
||||
|
||||
if(Condition->Operation < OP_EQUAL || Condition->Operation > OP_GREATE)
|
||||
Condition = ConstructASTBranch(OP_BOOLCONV, Condition->ExprType, Condition, 0);
|
||||
Condition = ConstructASTBranch(OP_BOOLCONV, Condition->ExprType, Condition, NULL, 0);
|
||||
|
||||
VerifyToken(LI_RPARE, ")");
|
||||
|
||||
Body = ParseCompound();
|
||||
|
||||
return ConstructASTNode(OP_LOOP, RET_NONE, Condition, NULL, Body, 0);
|
||||
return ConstructASTNode(OP_LOOP, RET_NONE, Condition, NULL, Body, NULL, 0);
|
||||
}
|
||||
|
||||
struct ASTNode* ForStatement() {
|
||||
|
@ -298,7 +307,7 @@ struct ASTNode* ForStatement() {
|
|||
Condition = ParsePrecedenceASTNode(0);
|
||||
|
||||
if(Condition->Operation < OP_EQUAL || Condition->Operation > OP_GREATE)
|
||||
Condition = ConstructASTBranch(OP_BOOLCONV, Condition->ExprType, Condition, 0);
|
||||
Condition = ConstructASTBranch(OP_BOOLCONV, Condition->ExprType, Condition, NULL, 0);
|
||||
|
||||
VerifyToken(LI_SEMIC, ";");
|
||||
|
||||
|
@ -308,13 +317,13 @@ struct ASTNode* ForStatement() {
|
|||
Body = ParseCompound();
|
||||
|
||||
// We need to be able to skip over the body and the postop, so we group them together.
|
||||
Tree = ConstructASTNode(OP_COMP, RET_NONE, Body, NULL, Postop, 0);
|
||||
Tree = ConstructASTNode(OP_COMP, RET_NONE, Body, NULL, Postop, NULL, 0);
|
||||
// We need to be able to jump to the top of the condition and fall through to the body,
|
||||
// so we group it with the last block
|
||||
Tree = ConstructASTNode(OP_LOOP, RET_NONE, Condition, NULL, Tree, 0);
|
||||
Tree = ConstructASTNode(OP_LOOP, RET_NONE, Condition, NULL, Tree, NULL, 0);
|
||||
|
||||
// We need to append the postop to the loop, to form the final for loop
|
||||
return ConstructASTNode(OP_COMP, RET_NONE, Preop, NULL, Tree, 0);
|
||||
return ConstructASTNode(OP_COMP, RET_NONE, Preop, NULL, Tree, NULL, 0);
|
||||
}
|
||||
|
||||
struct ASTNode* PrintStatement(void) {
|
||||
|
@ -333,9 +342,9 @@ struct ASTNode* PrintStatement(void) {
|
|||
DieDecimal("Attempting to print an invalid type:", RightType);
|
||||
|
||||
if(RightType)
|
||||
Tree = ConstructASTBranch(RightType, RET_INT, Tree, 0);
|
||||
Tree = ConstructASTBranch(RightType, RET_INT, Tree, NULL, 0);
|
||||
|
||||
Tree = ConstructASTBranch(OP_PRINT, RET_NONE, Tree, 0);
|
||||
Tree = ConstructASTBranch(OP_PRINT, RET_NONE, Tree, NULL, 0);
|
||||
|
||||
//ParseAST(Tree);
|
||||
|
||||
|
@ -345,7 +354,7 @@ struct ASTNode* PrintStatement(void) {
|
|||
|
||||
struct ASTNode* PostfixStatement() {
|
||||
struct ASTNode* Tree;
|
||||
int ID;
|
||||
struct SymbolTableEntry* Entry;
|
||||
|
||||
Tokenise(&CurrentToken);
|
||||
|
||||
|
@ -364,8 +373,7 @@ struct ASTNode* PostfixStatement() {
|
|||
// There's no guarantees that the variable is in
|
||||
// the symbol table, though.
|
||||
|
||||
ID = FindSymbol(CurrentIdentifier);
|
||||
if(ID == -1 || Symbols[ID].Structure != ST_VAR)
|
||||
if((Entry = FindSymbol(CurrentIdentifier)) == NULL || Entry->Structure != ST_VAR)
|
||||
DieMessage("Unknown Variable", CurrentIdentifier);
|
||||
|
||||
// Here we check for postincrement and postdecrement.
|
||||
|
@ -373,14 +381,14 @@ struct ASTNode* PostfixStatement() {
|
|||
switch(CurrentToken.type) {
|
||||
case PPMM_PLUS:
|
||||
Tokenise(&CurrentToken);
|
||||
Tree = ConstructASTLeaf(OP_POSTINC, Symbols[ID].Type, ID);
|
||||
Tree = ConstructASTLeaf(OP_POSTINC, Entry->Type, Entry, 0);
|
||||
break;
|
||||
case PPMM_MINUS:
|
||||
Tokenise(&CurrentToken);
|
||||
Tree = ConstructASTLeaf(OP_POSTDEC, Symbols[ID].Type, ID);
|
||||
Tree = ConstructASTLeaf(OP_POSTDEC, Entry->Type, Entry, 0);
|
||||
break;
|
||||
default:
|
||||
Tree = ConstructASTLeaf(REF_IDENT, Symbols[ID].Type, ID);
|
||||
Tree = ConstructASTLeaf(REF_IDENT, Entry->Type, Entry, 0);
|
||||
}
|
||||
|
||||
return Tree;
|
||||
|
@ -395,21 +403,21 @@ struct ASTNode* PrefixStatement() {
|
|||
Tokenise(&CurrentToken);
|
||||
Tree = PrefixStatement();
|
||||
Tree->RVal = 1;
|
||||
Tree = ConstructASTBranch(OP_BOOLNOT, Tree->ExprType, Tree, 0);
|
||||
Tree = ConstructASTBranch(OP_BOOLNOT, Tree->ExprType, Tree, NULL, 0);
|
||||
break;
|
||||
|
||||
case BIT_NOT:
|
||||
Tokenise(&CurrentToken);
|
||||
Tree = PrefixStatement();
|
||||
Tree->RVal = 1;
|
||||
Tree = ConstructASTBranch(OP_BITNOT, Tree->ExprType, Tree, 0);
|
||||
Tree = ConstructASTBranch(OP_BITNOT, Tree->ExprType, Tree, NULL, 0);
|
||||
break;
|
||||
|
||||
case AR_MINUS:
|
||||
Tokenise(&CurrentToken);
|
||||
Tree = PrefixStatement();
|
||||
|
||||
Tree = ConstructASTBranch(OP_NEGATE, Tree->ExprType, Tree, 0);
|
||||
Tree = ConstructASTBranch(OP_NEGATE, Tree->ExprType, Tree, NULL, 0);
|
||||
break;
|
||||
|
||||
case PPMM_PLUS:
|
||||
|
@ -418,7 +426,7 @@ struct ASTNode* PrefixStatement() {
|
|||
|
||||
if(Tree->Operation != REF_IDENT)
|
||||
Die("++ not followed by identifier");
|
||||
Tree = ConstructASTBranch(OP_PREINC, Tree->ExprType, Tree, 0);
|
||||
Tree = ConstructASTBranch(OP_PREINC, Tree->ExprType, Tree, NULL, 0);
|
||||
break;
|
||||
|
||||
case PPMM_MINUS:
|
||||
|
@ -428,7 +436,7 @@ struct ASTNode* PrefixStatement() {
|
|||
if(Tree->Operation != REF_IDENT)
|
||||
Die("-- not followed by identifier");
|
||||
|
||||
Tree = ConstructASTBranch(OP_PREDEC, Tree->ExprType, Tree, 0);
|
||||
Tree = ConstructASTBranch(OP_PREDEC, Tree->ExprType, Tree, NULL, 0);
|
||||
break;
|
||||
|
||||
case BIT_AND:
|
||||
|
@ -453,7 +461,7 @@ struct ASTNode* PrefixStatement() {
|
|||
if(Tree->Operation != REF_IDENT && Tree->Operation != OP_DEREF)
|
||||
Die("* must be followed by another * or an identifier.");
|
||||
|
||||
Tree = ConstructASTBranch(OP_DEREF, ValueAt(Tree->ExprType), Tree, 0);
|
||||
Tree = ConstructASTBranch(OP_DEREF, ValueAt(Tree->ExprType), Tree, NULL, 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
204
src/Symbols.c
204
src/Symbols.c
|
@ -7,105 +7,138 @@
|
|||
#include <Defs.h>
|
||||
#include <Data.h>
|
||||
|
||||
static int GlobalSymbols = 0;
|
||||
|
||||
|
||||
int FindSymbolImpl(char* Symbol, int Storage) {
|
||||
int Ind;
|
||||
|
||||
for(Ind = (Storage == SC_GLOBAL /* Are we global scope? */
|
||||
? 0 /* If so, start from the beginning */
|
||||
: CurrentLocal + 1 /* Else, go from the start of the local block */
|
||||
);
|
||||
Ind < (Storage == SC_GLOBAL /* Are we global scope? */
|
||||
? CurrentGlobal /* If so, start searching at the start */
|
||||
: SYMBOLS /* Otherwise, start at the end and work backward */
|
||||
);
|
||||
Ind++) {
|
||||
if(Storage == SC_GLOBAL && Symbols[Ind].Storage == SC_PARAM) continue; // Skip searching globals for parameters.
|
||||
if(*Symbol == *Symbols[Ind].Name && !strcmp(Symbol, Symbols[Ind].Name)) {
|
||||
printf("\t\tFound %s at %d\r\n", Symbol, Ind);
|
||||
return Ind;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the position of a symbol in the symbol table.
|
||||
* @Return the index into the symbol table if found,
|
||||
* -1 if not found.
|
||||
* Does not care about differentiating local or global.
|
||||
* It will only be consistent.
|
||||
* Find the position of a symbol in a given symbol table.
|
||||
* @param Name: The string name of the symbol
|
||||
* @param List: The linked list to search in.
|
||||
* @return the list if found,
|
||||
* NULL if no found.
|
||||
*/
|
||||
int FindSymbol(char* Symbol) {
|
||||
int Res;
|
||||
// Prioritise local vars
|
||||
if((Res = FindSymbolImpl(Symbol, SC_LOCAL)) == -1)
|
||||
// Fallback to global vars.
|
||||
return FindSymbolImpl(Symbol, SC_GLOBAL);
|
||||
return Res;
|
||||
|
||||
static struct SymbolTableEntry* SearchList(char* Name, struct SymbolTableEntry* List) {
|
||||
for(; List != NULL; List = List->NextSymbol)
|
||||
if((List->Name != NULL) && !strcmp(Name, List->Name))
|
||||
return (List);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Append a new entry to the table of global symbols.
|
||||
* @Return the index to the new entry
|
||||
* Search all the tables for a symbol.
|
||||
* Use the overrides for polluted types
|
||||
* eg. if you need a global from a local scope
|
||||
*
|
||||
* @param Symbol: The string name of the symbol to search for
|
||||
* @return the Node corresponding to the most likely
|
||||
* symbol required.
|
||||
*
|
||||
*
|
||||
* Will kill the program if we run out.
|
||||
* The death condition here is running into the local symbol table.
|
||||
* //TODO: Dump symbols on death?
|
||||
*/
|
||||
static int NewGlobalSymbol() {
|
||||
int Pos;
|
||||
struct SymbolTableEntry* FindSymbol(char* Symbol) {
|
||||
struct SymbolTableEntry* Node;
|
||||
|
||||
if((Pos = (CurrentGlobal++)) >= CurrentLocal) {
|
||||
printf("%d:%d\r\n", CurrentGlobal, CurrentLocal);
|
||||
Die("Too many Global symbols");
|
||||
if(CurrentFunction) {
|
||||
Node = SearchList(Symbol, FunctionEntry->Start);
|
||||
if(Node)
|
||||
return Node;
|
||||
}
|
||||
|
||||
Node = SearchList(Symbol, Locals);
|
||||
if(Node)
|
||||
return Node;
|
||||
|
||||
return Pos;
|
||||
return SearchList(Symbol, Globals);
|
||||
}
|
||||
|
||||
/*
|
||||
* Append a new entry to the table of local (function-local) symbols.
|
||||
* @Return the index to the new entry
|
||||
*
|
||||
* Will kill the program if we run out.
|
||||
* The death condition here is running into the global symbol table.
|
||||
* //TODO: Dump symbols on death?
|
||||
* An override for FindSymbol.
|
||||
* Searches only the parameters and local variables.
|
||||
* @param Symbol: The string name of the symbol to search for.
|
||||
* @return a pointer to the node if found, else NULL
|
||||
*/
|
||||
static int NewLocalSymbol() {
|
||||
int Pos;
|
||||
if((Pos = (CurrentLocal--)) <= CurrentGlobal)
|
||||
Die("Too many Local symbols");
|
||||
struct SymbolTableEntry* FindLocal(char* Symbol) {
|
||||
struct SymbolTableEntry* Node;
|
||||
|
||||
return Pos;
|
||||
if(FunctionEntry) {
|
||||
Node = SearchList(Symbol, FunctionEntry->Start);
|
||||
if(Node)
|
||||
return Node;
|
||||
}
|
||||
|
||||
return SearchList(Symbol, Locals);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset the local counter on functions.
|
||||
* An override for FindSymbol.
|
||||
* Searches only the global variables.
|
||||
* @param Symbol: The string name of the symbol to search for.
|
||||
* @return a pointer to the node if found, else NULL
|
||||
*
|
||||
*/
|
||||
struct SymbolTableEntry* FindGlobal(char* Symbol) {
|
||||
return SearchList(Symbol, Globals);
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a particular linked list,
|
||||
* Take Node and append it to the Tail.
|
||||
*
|
||||
* If there is no tail, set it to the Head.
|
||||
* This prevents orphaned lists.
|
||||
*
|
||||
* @param Head: The start of the desired linked list
|
||||
* @param Tail: The end of the desired linked list
|
||||
* @param Node: The new item to append
|
||||
*
|
||||
*/
|
||||
void AppendSymbol(struct SymbolTableEntry** Head, struct SymbolTableEntry** Tail, struct SymbolTableEntry* Node) {
|
||||
if(Head == NULL || Tail == NULL || Node == NULL)
|
||||
Die("Not enough data to append a symbol to the tables");
|
||||
|
||||
if(*Tail) {
|
||||
(*Tail)->NextSymbol = Node;
|
||||
*Tail = Node;
|
||||
} else {
|
||||
*Head = *Tail = Node;
|
||||
}
|
||||
|
||||
Node->NextSymbol = NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Reset the local variables of functions.
|
||||
*/
|
||||
|
||||
void FreeLocals() {
|
||||
CurrentLocal = SYMBOLS - 1;
|
||||
Locals = LocalsEnd = NULL;
|
||||
Params = ParamsEnd = NULL;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset all tables.
|
||||
*/
|
||||
void ClearTables() {
|
||||
Globals = GlobalsEnd = NULL;
|
||||
Locals = LocalsEnd = NULL;
|
||||
Params = ParamsEnd = NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Add a symbol to the tables, and set all the metadata.
|
||||
* Create a symbol item, and set all the metadata.
|
||||
* @param Name: The string representing the name of the symbol.
|
||||
* @param Type: The return type in terms of DataTypes enum values.
|
||||
* @param Structure: The type of symbol this is, in terms of StructureType enum.
|
||||
* @param Storage: The storage scope of this symbol. For functions this is always SC_GLOBAL (for now). Vars and Arrays can be GLOBAL or SC_LOCAL.
|
||||
* @param EndLabel: The label # to jump to to exit the function or array, where appropriate.
|
||||
* @param Length: The size of the struct/array in units of 1xbase
|
||||
* @param Length: The label # to jump to to exit the function or array, where appropriate.
|
||||
* The size of the struct/array in units of 1xbase
|
||||
*
|
||||
* @return The ID in the symbol table that now represents this symbol.
|
||||
* @return The SymbolTableEntry* pointer that corresponds to this newly constructed node.
|
||||
*/
|
||||
int AddSymbol(char* Name, int Type, int Structure, int Storage, int EndLabel, int Length) {
|
||||
struct SymbolTableEntry* AddSymbol(char* Name, int Type, int Structure, int Storage, int Length, int SinkOffset) {
|
||||
|
||||
int TableSlot;
|
||||
/* int TableSlot;
|
||||
int SinkOffset = 0;
|
||||
|
||||
if((TableSlot = FindSymbolImpl(Name, Storage)) != -1)
|
||||
|
@ -130,17 +163,32 @@ int AddSymbol(char* Name, int Type, int Structure, int Storage, int EndLabel, in
|
|||
TableSlot = NewLocalSymbol();
|
||||
SinkOffset = AsCalcOffset(Type);
|
||||
break;
|
||||
} */
|
||||
|
||||
struct SymbolTableEntry* Node =
|
||||
(struct SymbolTableEntry*) malloc(sizeof(struct SymbolTableEntry));
|
||||
|
||||
Node->Name = strdup(Name);
|
||||
Node->Type = Type;
|
||||
Node->Structure = Structure;
|
||||
Node->Storage = Storage;
|
||||
Node->Length = Length;
|
||||
Node->SinkOffset = SinkOffset;
|
||||
|
||||
switch(Storage) {
|
||||
case SC_GLOBAL:
|
||||
AppendSymbol(&Globals, &GlobalsEnd, Node);
|
||||
if(Structure != ST_FUNC) AsGlobalSymbol(Node);
|
||||
break;
|
||||
case SC_LOCAL:
|
||||
AppendSymbol(&Locals, &LocalsEnd, Node);
|
||||
break;
|
||||
case SC_PARAM:
|
||||
AppendSymbol(&Params, &ParamsEnd, Node);
|
||||
break;
|
||||
}
|
||||
|
||||
Symbols[TableSlot].Name = strdup(Name);
|
||||
Symbols[TableSlot].Type = Type;
|
||||
Symbols[TableSlot].Structure = Structure;
|
||||
Symbols[TableSlot].Storage = Storage;
|
||||
Symbols[TableSlot].Length = Length;
|
||||
Symbols[TableSlot].SinkOffset = SinkOffset;
|
||||
Symbols[TableSlot].EndLabel = EndLabel;
|
||||
|
||||
// NOTE: Generating global symbol names must happen AFTER the name and type are declared.
|
||||
/* // NOTE: Generating global symbol names must happen AFTER the name and type are declared.
|
||||
switch(Storage) {
|
||||
case SC_GLOBAL:
|
||||
printf("\tCreating new global symbol %s into slot %d\r\n", Name, TableSlot);
|
||||
|
@ -151,8 +199,8 @@ int AddSymbol(char* Name, int Type, int Structure, int Storage, int EndLabel, in
|
|||
break;
|
||||
case SC_LOCAL:
|
||||
break;
|
||||
}
|
||||
} */
|
||||
|
||||
//printf("Adding new variable %s of type %s to the table at %d\n", CurrentIdentifier, Types[Type], TableSlot);
|
||||
return TableSlot;
|
||||
return Node;
|
||||
}
|
40
src/Types.c
40
src/Types.c
|
@ -9,15 +9,11 @@
|
|||
|
||||
|
||||
int TypeIsInt(int Type) {
|
||||
if(Type == RET_CHAR || Type == RET_INT || Type == RET_LONG)
|
||||
return 1;
|
||||
return 0;
|
||||
return ((Type & 0xf) == 0);
|
||||
}
|
||||
|
||||
int TypeIsPtr(int Type) {
|
||||
if(Type == PTR_VOID || Type == PTR_CHAR || Type == PTR_INT || Type == PTR_LONG)
|
||||
return 1;
|
||||
return 0;
|
||||
return ((Type & 0xf) != 0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -33,10 +29,32 @@ int TypeIsPtr(int Type) {
|
|||
*/
|
||||
|
||||
int PrimitiveSize(int Type) {
|
||||
if(Type < RET_NONE || Type > PTR_VOID)
|
||||
DieDecimal("Checking size of bad data type", Type);
|
||||
|
||||
return TypeSizes[Type];
|
||||
if(TypeIsPtr(Type)) return 8;
|
||||
switch(Type) {
|
||||
case RET_CHAR: return 1;
|
||||
case RET_INT: return 4;
|
||||
case RET_LONG: return 8;
|
||||
default:
|
||||
DieDecimal("Bad type in PrimitiveSize", Type);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char TypeBuffer[7];
|
||||
|
||||
char* TypeNames(int Type) {
|
||||
switch(Type) {
|
||||
case RET_CHAR: memcpy(TypeBuffer, "Char", 4); break;
|
||||
case RET_INT: memcpy(TypeBuffer, "Int ", 4); break;
|
||||
case RET_LONG: memcpy(TypeBuffer, "Long", 4); break;
|
||||
case RET_VOID: memcpy(TypeBuffer, "Void", 4); break;
|
||||
default: DieDecimal("Bad size for printing", Type);
|
||||
};
|
||||
if(TypeIsPtr(Type)) memcpy((void*)((size_t) TypeBuffer + 4), "Ptr", 3);
|
||||
else memcpy((void*)((size_t) TypeBuffer + 4), " ", 3);
|
||||
return TypeBuffer;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -180,7 +198,7 @@ struct ASTNode* MutateType(struct ASTNode* Tree, int RightType, int Operation) {
|
|||
*/
|
||||
|
||||
if(RightSize > LeftSize)
|
||||
return ConstructASTBranch(OP_WIDEN, RightType, Tree, 0);
|
||||
return ConstructASTBranch(OP_WIDEN, RightType, Tree, NULL, 0);
|
||||
}
|
||||
|
||||
// Left branch pointers are compatible if we're not doing operations
|
||||
|
@ -206,7 +224,7 @@ struct ASTNode* MutateType(struct ASTNode* Tree, int RightType, int Operation) {
|
|||
RightSize = PrimitiveSize(ValueAt(RightType));
|
||||
|
||||
if(RightSize > 1)
|
||||
return ConstructASTBranch(OP_SCALE, RightType, Tree, RightSize);
|
||||
return ConstructASTBranch(OP_SCALE, RightType, Tree, NULL, RightSize);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user