CLion reformatting pass, finish struct implementation
This commit is contained in:
parent
ac8c0ed9c7
commit
537246daae
20
CMakeLists.txt
Normal file
20
CMakeLists.txt
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
cmake_minimum_required(VERSION 3.21)
|
||||||
|
project(Erythro C)
|
||||||
|
|
||||||
|
set(CMAKE_C_STANDARD 11)
|
||||||
|
|
||||||
|
include_directories(include)
|
||||||
|
|
||||||
|
add_executable(Erythro
|
||||||
|
include/Data.h
|
||||||
|
include/Defs.h
|
||||||
|
src/Assembler.c
|
||||||
|
src/Delegate.c
|
||||||
|
src/Dump.c
|
||||||
|
src/Lexer.c
|
||||||
|
src/Main.c
|
||||||
|
src/Parser.c
|
||||||
|
src/Pointers.c
|
||||||
|
src/Statements.c
|
||||||
|
src/Symbols.c
|
||||||
|
src/Types.c)
|
|
@ -4,6 +4,7 @@
|
||||||
/*************/
|
/*************/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <Defs.h>
|
#include <Defs.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
@ -15,14 +16,14 @@
|
||||||
#define TEXTLEN 512
|
#define TEXTLEN 512
|
||||||
#define SYMBOLS 1024
|
#define SYMBOLS 1024
|
||||||
|
|
||||||
extern_ struct SymbolTableEntry* Globals, *GlobalsEnd;
|
extern_ struct SymbolTableEntry* Globals, * GlobalsEnd;
|
||||||
extern_ struct SymbolTableEntry* Locals, *LocalsEnd;
|
extern_ struct SymbolTableEntry* Locals, * LocalsEnd;
|
||||||
extern_ struct SymbolTableEntry* Params, *ParamsEnd;
|
extern_ struct SymbolTableEntry* Params, * ParamsEnd;
|
||||||
extern_ struct SymbolTableEntry* Structs, *StructsEnd;
|
extern_ struct SymbolTableEntry* Structs, * StructsEnd;
|
||||||
extern_ struct SymbolTableEntry* StructMembers, *StructMembersEnd;
|
extern_ struct SymbolTableEntry* StructMembers, * StructMembersEnd;
|
||||||
|
|
||||||
extern_ struct SymbolTableEntry* Unions, *UnionsEnd;
|
extern_ struct SymbolTableEntry* Unions, * UnionsEnd;
|
||||||
extern_ struct SymbolTableEntry* Enums, *EnumsEnd;
|
extern_ struct SymbolTableEntry* Enums, * EnumsEnd;
|
||||||
|
|
||||||
extern_ bool OptDumpTree;
|
extern_ bool OptDumpTree;
|
||||||
extern_ bool OptKeepAssembly;
|
extern_ bool OptKeepAssembly;
|
||||||
|
@ -31,9 +32,9 @@ extern_ bool OptLinkFiles;
|
||||||
extern_ bool OptVerboseOutput;
|
extern_ bool OptVerboseOutput;
|
||||||
|
|
||||||
extern_ char* OutputFileName;
|
extern_ char* OutputFileName;
|
||||||
extern_ char* CurrentASMFile, *CurrentObjectFile;
|
extern_ char* CurrentASMFile, * CurrentObjectFile;
|
||||||
|
|
||||||
extern_ int TypeSizes[5];
|
extern_ int TypeSizes[5];
|
||||||
|
|
||||||
extern_ char* TokenNames[];
|
extern_ char* TokenNames[];
|
||||||
|
|
||||||
|
|
109
include/Defs.h
109
include/Defs.h
|
@ -4,6 +4,7 @@
|
||||||
/*************/
|
/*************/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
@ -88,7 +89,7 @@ enum TokenTypes {
|
||||||
TY_VOID, // "void" type keyword
|
TY_VOID, // "void" type keyword
|
||||||
|
|
||||||
KW_FUNC, // :: function name incoming
|
KW_FUNC, // :: function name incoming
|
||||||
|
|
||||||
KW_PRINT,
|
KW_PRINT,
|
||||||
KW_IF,
|
KW_IF,
|
||||||
KW_ELSE,
|
KW_ELSE,
|
||||||
|
@ -117,40 +118,40 @@ enum SyntaxOps {
|
||||||
OP_BOOLOR, // Boolean OR two statements
|
OP_BOOLOR, // Boolean OR two statements
|
||||||
OP_BOOLAND, // Boolean AND two statements
|
OP_BOOLAND, // Boolean AND two statements
|
||||||
OP_BITOR, // Bitwise OR a number
|
OP_BITOR, // Bitwise OR a number
|
||||||
OP_BITXOR, // Bitwise XOR a number
|
OP_BITXOR = 5, // Bitwise XOR a number
|
||||||
OP_BITAND, // Bitwise AND a number
|
OP_BITAND, // Bitwise AND a number
|
||||||
|
|
||||||
OP_EQUAL, // Compare equality
|
OP_EQUAL, // Compare equality
|
||||||
OP_INEQ, // Compare inequality
|
OP_INEQ, // Compare inequality
|
||||||
OP_LESS, // Less than?
|
OP_LESS, // Less than?
|
||||||
OP_GREAT, // Greater than?
|
OP_GREAT = 10, // Greater than?
|
||||||
OP_LESSE, // Less than or Equal to?
|
OP_LESSE, // Less than or Equal to?
|
||||||
OP_GREATE, // Greater than or Equal to?
|
OP_GREATE, // Greater than or Equal to?
|
||||||
|
|
||||||
OP_SHIFTL, // Arithmetic Shift Left (Multiply by 2)
|
OP_SHIFTL, // Arithmetic Shift Left (Multiply by 2)
|
||||||
OP_SHIFTR, // Arithmetic Shift Right (Divide by 2)
|
OP_SHIFTR, // Arithmetic Shift Right (Divide by 2)
|
||||||
|
|
||||||
OP_ADD, // Add two numbers.
|
OP_ADD = 15, // Add two numbers.
|
||||||
OP_SUBTRACT, // Subtract two numbers.
|
OP_SUBTRACT, // Subtract two numbers.
|
||||||
OP_MULTIPLY, // Multiply two numbers.
|
OP_MULTIPLY, // Multiply two numbers.
|
||||||
OP_DIVIDE, // Divide two numbers.
|
OP_DIVIDE, // Divide two numbers.
|
||||||
|
|
||||||
OP_PREINC, // Increment var before reference.
|
OP_PREINC, // Increment var before reference.
|
||||||
OP_PREDEC, // Decrement var before reference.
|
OP_PREDEC = 20, // Decrement var before reference.
|
||||||
OP_POSTINC, // Increment var after reference.
|
OP_POSTINC, // Increment var after reference.
|
||||||
OP_POSTDEC, // Decrement var after reference.
|
OP_POSTDEC, // Decrement var after reference.
|
||||||
|
|
||||||
OP_BITNOT, // Invert a number bitwise
|
OP_BITNOT, // Invert a number bitwise
|
||||||
OP_BOOLNOT, // Invert a statement logically
|
OP_BOOLNOT, // Invert a statement logically
|
||||||
OP_NEGATE, // Negate a number (turn a positive number negative)
|
OP_NEGATE = 25, // Negate a number (turn a positive number negative)
|
||||||
|
|
||||||
OP_BOOLCONV, // Convert an expression to a boolean.s
|
OP_BOOLCONV, // Convert an expression to a boolean.s
|
||||||
|
|
||||||
OP_ADDRESS, // Fetch the address of a var
|
OP_ADDRESS, // Fetch the address of a var
|
||||||
OP_DEREF, // Get the value of the address in a pointer
|
OP_DEREF, // Get the value of the address in a pointer
|
||||||
|
|
||||||
TERM_INTLITERAL, // Integer Literal. This is a virtual operation, so it's a terminal.
|
TERM_INTLITERAL, // Integer Literal. This is a virtual operation, so it's a terminal.
|
||||||
TERM_STRLITERAL, // String Literal. Also terminal.
|
TERM_STRLITERAL = 30, // String Literal. Also terminal.
|
||||||
|
|
||||||
REF_IDENT, // Reference (read) an identifier (variable).
|
REF_IDENT, // Reference (read) an identifier (variable).
|
||||||
|
|
||||||
|
@ -158,14 +159,14 @@ enum SyntaxOps {
|
||||||
OP_SCALE, // We have a pointer that needs to be scaled!
|
OP_SCALE, // We have a pointer that needs to be scaled!
|
||||||
|
|
||||||
OP_CALL, // Call a function
|
OP_CALL, // Call a function
|
||||||
OP_RET, // Return from a function
|
OP_RET = 35, // Return from a function
|
||||||
|
|
||||||
OP_COMP, // Compound statements need a way to be "glued" together. This is one of those mechanisms
|
OP_COMP, // Compound statements need a way to be "glued" together. This is one of those mechanisms
|
||||||
OP_IF, // If statement
|
OP_IF, // If statement
|
||||||
OP_LOOP, // FOR, WHILE
|
OP_LOOP, // FOR, WHILE
|
||||||
OP_PRINT, // Print statement
|
OP_PRINT, // Print statement
|
||||||
|
|
||||||
OP_FUNC, // Define a function
|
OP_FUNC = 40, // Define a function
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -220,11 +221,11 @@ enum StorageScope {
|
||||||
SC_STRUCT, // Struct Definitions
|
SC_STRUCT, // Struct Definitions
|
||||||
SC_ENUM, // Enum Definitions
|
SC_ENUM, // Enum Definitions
|
||||||
SC_MEMBER, // The members of Structs or Enums
|
SC_MEMBER, // The members of Structs or Enums
|
||||||
//SC_CLASS, // Class-local definitions
|
//SC_CLASS, // Class-local definitions
|
||||||
//SC_STATIC, // Static storage definitions
|
//SC_STATIC, // Static storage definitions
|
||||||
SC_PARAM, // Function parameters
|
SC_PARAM, // Function parameters
|
||||||
SC_LOCAL // Function-local scope.
|
SC_LOCAL // Function-local scope.
|
||||||
// There is no deeper scope than function.
|
// There is no deeper scope than function.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -243,7 +244,7 @@ enum DataTypes {
|
||||||
RET_INT = 32, // "int" type keyword
|
RET_INT = 32, // "int" type keyword
|
||||||
RET_LONG = 48, // "long" type keyword
|
RET_LONG = 48, // "long" type keyword
|
||||||
RET_VOID = 64, // "void" type keyword
|
RET_VOID = 64, // "void" type keyword
|
||||||
|
|
||||||
DAT_STRUCT = 80, // Struct Data
|
DAT_STRUCT = 80, // Struct Data
|
||||||
DAT_UNION, // Union Data
|
DAT_UNION, // Union Data
|
||||||
};
|
};
|
||||||
|
@ -258,8 +259,8 @@ enum StructureType {
|
||||||
ST_FUNC, // This is a function
|
ST_FUNC, // This is a function
|
||||||
ST_ARR, // This is an array
|
ST_ARR, // This is an array
|
||||||
ST_RUCT // This is a struct
|
ST_RUCT // This is a struct
|
||||||
// This is an enum
|
// This is an enum
|
||||||
// This is a typedef
|
// This is a typedef
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -268,9 +269,13 @@ enum StructureType {
|
||||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
char* Suffixate(char* String, char Suffix);
|
char* Suffixate(char* String, char Suffix);
|
||||||
|
|
||||||
char* Compile(char* InputFile);
|
char* Compile(char* InputFile);
|
||||||
|
|
||||||
char* Assemble(char* InputFile);
|
char* Assemble(char* InputFile);
|
||||||
|
|
||||||
void Link(char* Output, char* Objects[]);
|
void Link(char* Output, char* Objects[]);
|
||||||
|
|
||||||
void DisplayUsage(char* ProgName);
|
void DisplayUsage(char* ProgName);
|
||||||
|
|
||||||
|
|
||||||
|
@ -282,9 +287,11 @@ void DisplayUsage(char* ProgName);
|
||||||
void Tokenise();
|
void Tokenise();
|
||||||
|
|
||||||
void VerifyToken(int Type, char* TokenExpected);
|
void VerifyToken(int Type, char* TokenExpected);
|
||||||
|
|
||||||
void RejectToken(struct Token* Token);
|
void RejectToken(struct Token* Token);
|
||||||
|
|
||||||
static int ReadIdentifier(int Char, char* Buffer, int Limit);
|
static int ReadIdentifier(int Char, char* Buffer, int Limit);
|
||||||
|
|
||||||
static int ReadKeyword(char* Str);
|
static int ReadKeyword(char* Str);
|
||||||
|
|
||||||
/* * * * * * * * * * * * * * * * * * * *
|
/* * * * * * * * * * * * * * * * * * * *
|
||||||
|
@ -294,9 +301,11 @@ static int ReadKeyword(char* Str);
|
||||||
struct ASTNode* MutateType(struct ASTNode* Tree, int RightType, int Operation);
|
struct ASTNode* MutateType(struct ASTNode* Tree, int RightType, int Operation);
|
||||||
|
|
||||||
int TypeIsInt(int Type);
|
int TypeIsInt(int Type);
|
||||||
|
|
||||||
int TypeIsPtr(int Type);
|
int TypeIsPtr(int Type);
|
||||||
|
|
||||||
char* TypeNames(int Type);
|
char* TypeNames(int Type);
|
||||||
|
|
||||||
int TypeSize(int Type, struct SymbolTableEntry* Composite);
|
int TypeSize(int Type, struct SymbolTableEntry* Composite);
|
||||||
|
|
||||||
|
|
||||||
|
@ -314,7 +323,8 @@ struct ASTNode* ConstructASTNode(int Operation, int Type,
|
||||||
|
|
||||||
struct ASTNode* ConstructASTLeaf(int Operation, int Type, struct SymbolTableEntry* Symbol, int IntValue);
|
struct ASTNode* ConstructASTLeaf(int Operation, int Type, struct SymbolTableEntry* Symbol, int IntValue);
|
||||||
|
|
||||||
struct ASTNode* ConstructASTBranch(int Operation, int Type, struct ASTNode* Left, struct SymbolTableEntry* Symbol, int IntValue);
|
struct ASTNode*
|
||||||
|
ConstructASTBranch(int Operation, int Type, struct ASTNode* Left, struct SymbolTableEntry* Symbol, int IntValue);
|
||||||
|
|
||||||
|
|
||||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
@ -325,25 +335,35 @@ struct ASTNode* ParsePrecedenceASTNode(int PreviousTokenPrecedence);
|
||||||
|
|
||||||
|
|
||||||
struct ASTNode* ParsePrimary(void);
|
struct ASTNode* ParsePrimary(void);
|
||||||
|
|
||||||
struct ASTNode* ParseStatement(void);
|
struct ASTNode* ParseStatement(void);
|
||||||
|
|
||||||
struct ASTNode* PrefixStatement();
|
struct ASTNode* PrefixStatement();
|
||||||
|
|
||||||
struct ASTNode* PostfixStatement();
|
struct ASTNode* PostfixStatement();
|
||||||
|
|
||||||
void ParseGlobals();
|
void ParseGlobals();
|
||||||
|
|
||||||
struct ASTNode* ParseFunction(int Type);
|
struct ASTNode* ParseFunction(int Type);
|
||||||
|
|
||||||
struct ASTNode* ParseCompound();
|
struct ASTNode* ParseCompound();
|
||||||
|
|
||||||
struct SymbolTableEntry* BeginStructDeclaration();
|
struct SymbolTableEntry* BeginStructDeclaration();
|
||||||
|
|
||||||
struct ASTNode* GetExpressionList();
|
struct ASTNode* GetExpressionList();
|
||||||
|
|
||||||
struct ASTNode* CallFunction();
|
struct ASTNode* CallFunction();
|
||||||
|
|
||||||
struct ASTNode* ReturnStatement();
|
struct ASTNode* ReturnStatement();
|
||||||
|
|
||||||
int ParseOptionalPointer(struct SymbolTableEntry** Composite);
|
int ParseOptionalPointer(struct SymbolTableEntry** Composite);
|
||||||
|
|
||||||
int ValueAt(int Type);
|
int ValueAt(int Type);
|
||||||
|
|
||||||
int PointerTo(int Type);
|
int PointerTo(int Type);
|
||||||
|
|
||||||
struct ASTNode* AccessArray();
|
struct ASTNode* AccessArray();
|
||||||
|
|
||||||
struct ASTNode* AccessMember(bool Deref);
|
struct ASTNode* AccessMember(bool Deref);
|
||||||
|
|
||||||
int ParseTokenToOperation(int Token);
|
int ParseTokenToOperation(int Token);
|
||||||
|
@ -351,35 +371,45 @@ int ParseTokenToOperation(int Token);
|
||||||
struct ASTNode* PrintStatement(void);
|
struct ASTNode* PrintStatement(void);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
* * * * * * S Y M B O L T A B L E * * * * * *
|
* * * * * * S Y M B O L T A B L E * * * * * *
|
||||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
void DumpAllLists();
|
void DumpAllLists();
|
||||||
|
|
||||||
void DumpList(struct SymbolTableEntry* List);
|
void DumpList(struct SymbolTableEntry* List);
|
||||||
|
|
||||||
struct SymbolTableEntry* FindSymbol(char* Symbol);
|
struct SymbolTableEntry* FindSymbol(char* Symbol);
|
||||||
|
|
||||||
struct SymbolTableEntry* FindLocal(char* Symbol);
|
struct SymbolTableEntry* FindLocal(char* Symbol);
|
||||||
|
|
||||||
struct SymbolTableEntry* FindGlobal(char* Symbol);
|
struct SymbolTableEntry* FindGlobal(char* Symbol);
|
||||||
|
|
||||||
struct SymbolTableEntry* FindStruct(char* Symbol);
|
struct SymbolTableEntry* FindStruct(char* Symbol);
|
||||||
|
|
||||||
struct SymbolTableEntry* FindMember(char* Symbol);
|
struct SymbolTableEntry* FindMember(char* Symbol);
|
||||||
|
|
||||||
void AppendSymbol(struct SymbolTableEntry** Head, struct SymbolTableEntry** Tail, struct SymbolTableEntry* Node);
|
void AppendSymbol(struct SymbolTableEntry** Head, struct SymbolTableEntry** Tail, struct SymbolTableEntry* Node);
|
||||||
|
|
||||||
void FreeLocals();
|
void FreeLocals();
|
||||||
|
|
||||||
void ClearTables();
|
void ClearTables();
|
||||||
|
|
||||||
struct SymbolTableEntry* AddSymbol(char* Name, int Type, int Structure, int Storage, int Length, int SinkOffset, struct SymbolTableEntry* CompositeType);
|
struct SymbolTableEntry* AddSymbol(char* Name, int Type, int Structure, int Storage, int Length, int SinkOffset,
|
||||||
|
struct SymbolTableEntry* CompositeType);
|
||||||
|
|
||||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
* * * * C O N T R O L S T A T U S * * * *
|
* * * * C O N T R O L S T A T U S * * * *
|
||||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
void Die(char* Error);
|
void Die(char* Error);
|
||||||
|
|
||||||
void DieMessage(char* Error, char* Reason);
|
void DieMessage(char* Error, char* Reason);
|
||||||
|
|
||||||
void DieDecimal(char* Error, int Number);
|
void DieDecimal(char* Error, int Number);
|
||||||
|
|
||||||
void DieChar(char* Error, int Char);
|
void DieChar(char* Error, int Char);
|
||||||
|
|
||||||
void DieBinary(char* Error, int Number);
|
void DieBinary(char* Error, int Number);
|
||||||
|
|
||||||
|
|
||||||
|
@ -396,62 +426,94 @@ int RetrieveRegister();
|
||||||
void DeallocateRegister(int Register);
|
void DeallocateRegister(int Register);
|
||||||
|
|
||||||
int PrimitiveSize(int Type);
|
int PrimitiveSize(int Type);
|
||||||
|
|
||||||
int AsAlignMemory(int Type, int Offset, int Direction);
|
int AsAlignMemory(int Type, int Offset, int Direction);
|
||||||
|
|
||||||
int AsLoad(int Value);
|
int AsLoad(int Value);
|
||||||
|
|
||||||
int AsAdd(int Left, int Right);
|
int AsAdd(int Left, int Right);
|
||||||
|
|
||||||
int AsMul(int Left, int Right);
|
int AsMul(int Left, int Right);
|
||||||
|
|
||||||
int AsSub(int Left, int Right);
|
int AsSub(int Left, int Right);
|
||||||
|
|
||||||
int AsDiv(int Left, int Right);
|
int AsDiv(int Left, int Right);
|
||||||
|
|
||||||
int AsLdGlobalVar(struct SymbolTableEntry* Entry, int Operation);
|
int AsLdGlobalVar(struct SymbolTableEntry* Entry, int Operation);
|
||||||
|
|
||||||
int AsLdLocalVar(struct SymbolTableEntry* Entry, int Operation);
|
int AsLdLocalVar(struct SymbolTableEntry* Entry, int Operation);
|
||||||
|
|
||||||
int AsStrGlobalVar(struct SymbolTableEntry* Entry, int Register);
|
int AsStrGlobalVar(struct SymbolTableEntry* Entry, int Register);
|
||||||
|
|
||||||
int AsStrLocalVar(struct SymbolTableEntry* Entry, int Register);
|
int AsStrLocalVar(struct SymbolTableEntry* Entry, int Register);
|
||||||
|
|
||||||
int AsCalcOffset(int Type);
|
int AsCalcOffset(int Type);
|
||||||
|
|
||||||
void AsNewStackFrame();
|
void AsNewStackFrame();
|
||||||
|
|
||||||
int AsDeref(int Reg, int Type);
|
int AsDeref(int Reg, int Type);
|
||||||
|
|
||||||
int AsStrDeref(int Register1, int Register2, int Type);
|
int AsStrDeref(int Register1, int Register2, int Type);
|
||||||
|
|
||||||
int AsAddr(struct SymbolTableEntry* Entry);
|
int AsAddr(struct SymbolTableEntry* Entry);
|
||||||
|
|
||||||
void AsGlobalSymbol(struct SymbolTableEntry* Entry);
|
void AsGlobalSymbol(struct SymbolTableEntry* Entry);
|
||||||
int AsNewString(char* Value);
|
|
||||||
|
int AsNewString(char* Value);
|
||||||
|
|
||||||
|
|
||||||
int AsLoadString(int ID);
|
int AsLoadString(int ID);
|
||||||
|
|
||||||
int AsEqual(int Left, int Right);
|
int AsEqual(int Left, int Right);
|
||||||
|
|
||||||
int AsIneq(int Left, int Right);
|
int AsIneq(int Left, int Right);
|
||||||
|
|
||||||
int AsLess(int Left, int Right);
|
int AsLess(int Left, int Right);
|
||||||
|
|
||||||
int AsGreat(int Left, int Right);
|
int AsGreat(int Left, int Right);
|
||||||
|
|
||||||
int AsLessE(int Left, int Right);
|
int AsLessE(int Left, int Right);
|
||||||
|
|
||||||
int AsGreatE(int Left, int Right);
|
int AsGreatE(int Left, int Right);
|
||||||
|
|
||||||
int AsBitwiseAND(int Left, int Right);
|
int AsBitwiseAND(int Left, int Right);
|
||||||
|
|
||||||
int AsBitwiseOR(int Left, int Right);
|
int AsBitwiseOR(int Left, int Right);
|
||||||
|
|
||||||
int AsBitwiseXOR(int Left, int Right);
|
int AsBitwiseXOR(int Left, int Right);
|
||||||
|
|
||||||
int AsNegate(int Register);
|
int AsNegate(int Register);
|
||||||
|
|
||||||
int AsInvert(int Register);
|
int AsInvert(int Register);
|
||||||
|
|
||||||
int AsBooleanNOT(int Register);
|
int AsBooleanNOT(int Register);
|
||||||
|
|
||||||
int AsShiftLeft(int Left, int Right);
|
int AsShiftLeft(int Left, int Right);
|
||||||
|
|
||||||
int AsShiftRight(int Left, int Right);
|
int AsShiftRight(int Left, int Right);
|
||||||
|
|
||||||
int AsBooleanConvert(int Register, int Operation, int Label);
|
int AsBooleanConvert(int Register, int Operation, int Label);
|
||||||
|
|
||||||
int AsCompareJmp(int Operation, int RegisterLeft, int RegisterRight, int Label);
|
int AsCompareJmp(int Operation, int RegisterLeft, int RegisterRight, int Label);
|
||||||
|
|
||||||
int AsCompare(int Operation, int RegisterLeft, int RegisterRight);
|
int AsCompare(int Operation, int RegisterLeft, int RegisterRight);
|
||||||
|
|
||||||
int AsIf(struct ASTNode* Node);
|
int AsIf(struct ASTNode* Node);
|
||||||
|
|
||||||
int NewLabel(void);
|
int NewLabel(void);
|
||||||
|
|
||||||
void AsJmp(int Label);
|
void AsJmp(int Label);
|
||||||
|
|
||||||
void AsLabel(int Label);
|
void AsLabel(int Label);
|
||||||
|
|
||||||
int AsShl(int Register, int Val);
|
int AsShl(int Register, int Val);
|
||||||
|
|
||||||
int AsReturn(struct SymbolTableEntry* Entry, int Register);
|
int AsReturn(struct SymbolTableEntry* Entry, int Register);
|
||||||
|
|
||||||
int AsCallWrapper(struct ASTNode* Node);
|
int AsCallWrapper(struct ASTNode* Node);
|
||||||
|
|
||||||
void AsCopyArgs(int Register, int Position);
|
void AsCopyArgs(int Register, int Position);
|
||||||
|
|
||||||
int AsCall(struct SymbolTableEntry* Entry, int Args);
|
int AsCall(struct SymbolTableEntry* Entry, int Args);
|
||||||
|
|
||||||
int AsWhile(struct ASTNode* Node);
|
int AsWhile(struct ASTNode* Node);
|
||||||
|
@ -459,7 +521,9 @@ int AsWhile(struct ASTNode* Node);
|
||||||
void AssemblerPrint(int Register);
|
void AssemblerPrint(int Register);
|
||||||
|
|
||||||
void AssemblerPreamble();
|
void AssemblerPreamble();
|
||||||
|
|
||||||
void AsFunctionPreamble(struct SymbolTableEntry* Entry);
|
void AsFunctionPreamble(struct SymbolTableEntry* Entry);
|
||||||
|
|
||||||
void AsFunctionEpilogue(struct SymbolTableEntry* Entry);
|
void AsFunctionEpilogue(struct SymbolTableEntry* Entry);
|
||||||
|
|
||||||
|
|
||||||
|
@ -468,10 +532,13 @@ void AsFunctionEpilogue(struct SymbolTableEntry* Entry);
|
||||||
* * * * * * * * * * * * * * * * * * * * * * */
|
* * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
struct SymbolTableEntry* BeginVariableDeclaration(int Type, struct SymbolTableEntry* Composite, int Scope);
|
struct SymbolTableEntry* BeginVariableDeclaration(int Type, struct SymbolTableEntry* Composite, int Scope);
|
||||||
|
|
||||||
struct ASTNode* ParseIdentifier(void);
|
struct ASTNode* ParseIdentifier(void);
|
||||||
|
|
||||||
struct ASTNode* IfStatement();
|
struct ASTNode* IfStatement();
|
||||||
|
|
||||||
struct ASTNode* WhileStatement();
|
struct ASTNode* WhileStatement();
|
||||||
|
|
||||||
struct ASTNode* ForStatement();
|
struct ASTNode* ForStatement();
|
||||||
|
|
||||||
|
|
||||||
|
|
363
src/Assembler.c
363
src/Assembler.c
|
@ -29,17 +29,17 @@ static int UsedRegisters[4];
|
||||||
*
|
*
|
||||||
* The 4 clobber registers are first, and the 4 parameter registers are last.
|
* The 4 clobber registers are first, and the 4 parameter registers are last.
|
||||||
*/
|
*/
|
||||||
static char* Registers[8] = { "%r10", "%r11" , "%r12" , "%r13", "%r9" , "%r8", "%rdx", "%rcx" };
|
static char* Registers[8] = {"%r10", "%r11", "%r12", "%r13", "%r9", "%r8", "%rdx", "%rcx"};
|
||||||
static char* DoubleRegisters[8] = { "%r10d", "%r11d", "%r12d", "%r13d", "%r9d", "%r8d", "%edx", "%ecx" };
|
static char* DoubleRegisters[8] = {"%r10d", "%r11d", "%r12d", "%r13d", "%r9d", "%r8d", "%edx", "%ecx"};
|
||||||
static char* ByteRegisters[8] = { "%r10b", "%r11b", "%r12b", "%r13b", "%r9b", "%r8b", "%dl" , "%cl" };
|
static char* ByteRegisters[8] = {"%r10b", "%r11b", "%r12b", "%r13b", "%r9b", "%r8b", "%dl", "%cl"};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For ease of reading later code, we store the valid x86 comparison instructions,
|
* For ease of reading later code, we store the valid x86 comparison instructions,
|
||||||
* and the inverse jump instructions together, in a synchronized fashion.
|
* and the inverse jump instructions together, in a synchronized fashion.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static char* Comparisons[6] = { "sete", "setne", "setl", "setg", "setle", "setge" };
|
static char* Comparisons[6] = {"sete", "setne", "setl", "setg", "setle", "setge"};
|
||||||
static char* InvComparisons[6] = { "jne", "je", "jge", "jle", "jg", "jl"};
|
static char* InvComparisons[6] = {"jne", "je", "jge", "jle", "jg", "jl"};
|
||||||
|
|
||||||
// How far above the base pointer is the last local?
|
// How far above the base pointer is the last local?
|
||||||
static int LocalVarOffset;
|
static int LocalVarOffset;
|
||||||
|
@ -66,15 +66,15 @@ static int Started = 0;
|
||||||
*/
|
*/
|
||||||
int AssembleTree(struct ASTNode* Node, int Register, int ParentOp) {
|
int AssembleTree(struct ASTNode* Node, int Register, int ParentOp) {
|
||||||
int LeftVal, RightVal;
|
int LeftVal, RightVal;
|
||||||
if(!Started && OptDumpTree)
|
if (!Started && OptDumpTree)
|
||||||
DumpTree(Node, 0);
|
DumpTree(Node, 0);
|
||||||
Started = 1;
|
Started = 1;
|
||||||
|
|
||||||
printf("Current operation: %d\r\n", Node->Operation);
|
printf("Current operation: %d\r\n", Node->Operation);
|
||||||
switch(Node->Operation) {
|
switch (Node->Operation) {
|
||||||
case OP_IF:
|
case OP_IF:
|
||||||
return AsIf(Node);
|
return AsIf(Node);
|
||||||
|
|
||||||
case OP_LOOP:
|
case OP_LOOP:
|
||||||
return AsWhile(Node);
|
return AsWhile(Node);
|
||||||
|
|
||||||
|
@ -96,13 +96,13 @@ int AssembleTree(struct ASTNode* Node, int Register, int ParentOp) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if(Node->Left)
|
if (Node->Left)
|
||||||
LeftVal = AssembleTree(Node->Left, -1, Node->Operation);
|
LeftVal = AssembleTree(Node->Left, -1, Node->Operation);
|
||||||
|
|
||||||
if(Node->Right)
|
if (Node->Right)
|
||||||
RightVal = AssembleTree(Node->Right, LeftVal, Node->Operation);
|
RightVal = AssembleTree(Node->Right, LeftVal, Node->Operation);
|
||||||
|
|
||||||
switch(Node->Operation) {
|
switch (Node->Operation) {
|
||||||
case OP_ADD:
|
case OP_ADD:
|
||||||
return AsAdd(LeftVal, RightVal);
|
return AsAdd(LeftVal, RightVal);
|
||||||
|
|
||||||
|
@ -111,18 +111,21 @@ int AssembleTree(struct ASTNode* Node, int Register, int ParentOp) {
|
||||||
|
|
||||||
case OP_MULTIPLY:
|
case OP_MULTIPLY:
|
||||||
return AsMul(LeftVal, RightVal);
|
return AsMul(LeftVal, RightVal);
|
||||||
|
|
||||||
case OP_DIVIDE:
|
case OP_DIVIDE:
|
||||||
return AsDiv(LeftVal, RightVal);
|
return AsDiv(LeftVal, RightVal);
|
||||||
|
|
||||||
case OP_SCALE:
|
case OP_SCALE:
|
||||||
// We can (ab)use the powers of 2 to do
|
// We can (ab)use the powers of 2 to do
|
||||||
// efficient scaling with bitshifting.
|
// efficient scaling with bitshifting.
|
||||||
switch(Node->Size) {
|
switch (Node->Size) {
|
||||||
case 2: return AsShl(LeftVal, 1);
|
case 2:
|
||||||
case 4: return AsShl(LeftVal, 2);
|
return AsShl(LeftVal, 1);
|
||||||
case 8: return AsShl(LeftVal, 3);
|
case 4:
|
||||||
|
return AsShl(LeftVal, 2);
|
||||||
|
case 8:
|
||||||
|
return AsShl(LeftVal, 3);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
RightVal = AsLoad(Node->Size);
|
RightVal = AsLoad(Node->Size);
|
||||||
return AsMul(LeftVal, RightVal);
|
return AsMul(LeftVal, RightVal);
|
||||||
|
@ -135,25 +138,27 @@ int AssembleTree(struct ASTNode* Node, int Register, int ParentOp) {
|
||||||
|
|
||||||
case OP_ASSIGN:
|
case OP_ASSIGN:
|
||||||
printf("Preparing for assignment..\r\n");
|
printf("Preparing for assignment..\r\n");
|
||||||
if(Node->Right == NULL)
|
if (Node->Right == NULL)
|
||||||
Die("Fault in assigning a null rvalue");
|
Die("Fault in assigning a null rvalue");
|
||||||
|
|
||||||
printf("\tCalculating assignment for target %s:\r\n", Node->Right->Symbol->Name);
|
printf("\tCalculating assignment for target %s:\r\n", Node->Right->Symbol->Name);
|
||||||
switch(Node->Right->Operation) {
|
switch (Node->Right->Operation) {
|
||||||
case REF_IDENT:
|
case REF_IDENT:
|
||||||
if(Node->Right->Symbol->Storage == SC_LOCAL)
|
if (Node->Right->Symbol->Storage == SC_LOCAL)
|
||||||
return AsStrLocalVar(Node->Right->Symbol, LeftVal);
|
return AsStrLocalVar(Node->Right->Symbol, LeftVal);
|
||||||
else
|
else
|
||||||
return AsStrGlobalVar(Node->Right->Symbol, LeftVal);
|
return AsStrGlobalVar(Node->Right->Symbol, LeftVal);
|
||||||
|
|
||||||
case OP_DEREF: return AsStrDeref(LeftVal, RightVal, Node->Right->ExprType);
|
case OP_DEREF:
|
||||||
default: DieDecimal("Can't ASSIGN in AssembleTree: ", Node->Operation);
|
return AsStrDeref(LeftVal, RightVal, Node->Right->ExprType);
|
||||||
|
default:
|
||||||
|
DieDecimal("Can't ASSIGN in AssembleTree: ", Node->Operation);
|
||||||
}
|
}
|
||||||
|
|
||||||
case OP_WIDEN:
|
case OP_WIDEN:
|
||||||
printf("\tWidening types..\r\n");
|
printf("\tWidening types..\r\n");
|
||||||
return LeftVal;
|
return LeftVal;
|
||||||
|
|
||||||
case OP_RET:
|
case OP_RET:
|
||||||
printf("\tReturning from %s\n", Node->Symbol->Name);
|
printf("\tReturning from %s\n", Node->Symbol->Name);
|
||||||
AsReturn(FunctionEntry, LeftVal);
|
AsReturn(FunctionEntry, LeftVal);
|
||||||
|
@ -165,24 +170,28 @@ int AssembleTree(struct ASTNode* Node, int Register, int ParentOp) {
|
||||||
case OP_GREAT:
|
case OP_GREAT:
|
||||||
case OP_LESSE:
|
case OP_LESSE:
|
||||||
case OP_GREATE:
|
case OP_GREATE:
|
||||||
if(ParentOp == OP_IF || ParentOp == OP_LOOP)
|
if (ParentOp == OP_IF || ParentOp == OP_LOOP)
|
||||||
return AsCompareJmp(Node->Operation, LeftVal, RightVal, Register);
|
return AsCompareJmp(Node->Operation, LeftVal, RightVal, Register);
|
||||||
else
|
else
|
||||||
return AsCompare(Node->Operation, LeftVal, RightVal);
|
return AsCompare(Node->Operation, LeftVal, RightVal);
|
||||||
|
|
||||||
|
|
||||||
case REF_IDENT:
|
case REF_IDENT:
|
||||||
if(Node->RVal || ParentOp == OP_DEREF) {
|
if (TypeIsPtr(Node->ExprType)) {
|
||||||
if(Node->Symbol->Storage == SC_LOCAL || Node->Symbol->Storage == SC_PARAM)
|
return AsAddr(Node->Symbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Node->RVal || ParentOp == OP_DEREF) {
|
||||||
|
if (Node->Symbol->Storage == SC_LOCAL || Node->Symbol->Storage == SC_PARAM)
|
||||||
return AsLdLocalVar(Node->Symbol, Node->Operation);
|
return AsLdLocalVar(Node->Symbol, Node->Operation);
|
||||||
else
|
else
|
||||||
return AsLdGlobalVar(Node->Symbol, Node->Operation);
|
return AsLdGlobalVar(Node->Symbol, Node->Operation);
|
||||||
} else
|
} else
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
case TERM_INTLITERAL:
|
case TERM_INTLITERAL:
|
||||||
return AsLoad(Node->IntValue);
|
return AsLoad(Node->IntValue);
|
||||||
|
|
||||||
case TERM_STRLITERAL:
|
case TERM_STRLITERAL:
|
||||||
return AsLoadString(Node->IntValue);
|
return AsLoadString(Node->IntValue);
|
||||||
|
|
||||||
|
@ -193,40 +202,40 @@ int AssembleTree(struct ASTNode* Node, int Register, int ParentOp) {
|
||||||
|
|
||||||
case OP_BITAND:
|
case OP_BITAND:
|
||||||
return AsBitwiseAND(LeftVal, RightVal);
|
return AsBitwiseAND(LeftVal, RightVal);
|
||||||
|
|
||||||
case OP_BITOR:
|
case OP_BITOR:
|
||||||
return AsBitwiseOR(LeftVal, RightVal);
|
return AsBitwiseOR(LeftVal, RightVal);
|
||||||
|
|
||||||
case OP_BITXOR:
|
case OP_BITXOR:
|
||||||
return AsBitwiseXOR(LeftVal, RightVal);
|
return AsBitwiseXOR(LeftVal, RightVal);
|
||||||
|
|
||||||
case OP_SHIFTL:
|
case OP_SHIFTL:
|
||||||
return AsShiftLeft(LeftVal, RightVal);
|
return AsShiftLeft(LeftVal, RightVal);
|
||||||
|
|
||||||
case OP_SHIFTR:
|
case OP_SHIFTR:
|
||||||
return AsShiftRight(LeftVal, RightVal);
|
return AsShiftRight(LeftVal, RightVal);
|
||||||
|
|
||||||
case OP_POSTINC:
|
case OP_POSTINC:
|
||||||
return AsLdGlobalVar(Node->Symbol, Node->Operation);
|
return AsLdGlobalVar(Node->Symbol, Node->Operation);
|
||||||
|
|
||||||
case OP_POSTDEC:
|
case OP_POSTDEC:
|
||||||
return AsLdGlobalVar(Node->Symbol, Node->Operation);
|
return AsLdGlobalVar(Node->Symbol, Node->Operation);
|
||||||
|
|
||||||
case OP_PREINC:
|
case OP_PREINC:
|
||||||
return AsLdGlobalVar(Node->Symbol, Node->Operation);
|
return AsLdGlobalVar(Node->Symbol, Node->Operation);
|
||||||
|
|
||||||
case OP_PREDEC:
|
case OP_PREDEC:
|
||||||
return AsLdGlobalVar(Node->Symbol, Node->Operation);
|
return AsLdGlobalVar(Node->Symbol, Node->Operation);
|
||||||
|
|
||||||
case OP_BOOLNOT:
|
case OP_BOOLNOT:
|
||||||
return AsBooleanNOT(LeftVal);
|
return AsBooleanNOT(LeftVal);
|
||||||
|
|
||||||
case OP_BITNOT:
|
case OP_BITNOT:
|
||||||
return AsInvert(LeftVal);
|
return AsInvert(LeftVal);
|
||||||
|
|
||||||
case OP_NEGATE:
|
case OP_NEGATE:
|
||||||
return AsNegate(LeftVal);
|
return AsNegate(LeftVal);
|
||||||
|
|
||||||
case OP_BOOLCONV:
|
case OP_BOOLCONV:
|
||||||
return AsBooleanConvert(LeftVal, ParentOp, Register);
|
return AsBooleanConvert(LeftVal, ParentOp, Register);
|
||||||
|
|
||||||
|
@ -250,7 +259,7 @@ void DeallocateAllRegisters() {
|
||||||
*/
|
*/
|
||||||
int RetrieveRegister() {
|
int RetrieveRegister() {
|
||||||
for (size_t i = 0; i < 4; i++) {
|
for (size_t i = 0; i < 4; i++) {
|
||||||
if(UsedRegisters[i] == 0) {
|
if (UsedRegisters[i] == 0) {
|
||||||
UsedRegisters[i] = 1;
|
UsedRegisters[i] = 1;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
@ -265,7 +274,7 @@ int RetrieveRegister() {
|
||||||
* @param Register: The Registers index to deallocate.
|
* @param Register: The Registers index to deallocate.
|
||||||
*/
|
*/
|
||||||
void DeallocateRegister(int Register) {
|
void DeallocateRegister(int Register) {
|
||||||
if(UsedRegisters[Register] != 1) {
|
if (UsedRegisters[Register] != 1) {
|
||||||
fprintf(stderr, "Error trying to free register %d\n", Register);
|
fprintf(stderr, "Error trying to free register %d\n", Register);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
@ -328,27 +337,30 @@ int NewLabel(void) {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
int AsAlignMemory(int Type, int Offset, int Direction) {
|
int AsAlignMemory(int Type, int Offset, int Direction) {
|
||||||
switch(Type) {
|
switch (Type) {
|
||||||
case RET_CHAR: return Offset;
|
case RET_CHAR:
|
||||||
case RET_INT: case RET_LONG: break;
|
return Offset;
|
||||||
default:
|
case RET_INT:
|
||||||
DieDecimal("Unable to align type", Type);
|
case RET_LONG:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DieDecimal("Unable to align type", Type);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Alignment = 4;
|
int Alignment = 4;
|
||||||
Offset = (Offset + Direction * (Alignment-1)) & ~(Alignment-1);
|
Offset = (Offset + Direction * (Alignment - 1)) & ~(Alignment - 1);
|
||||||
return (Offset);
|
return (Offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assemble an If statement
|
// Assemble an If statement
|
||||||
int AsIf(struct ASTNode* Node) {
|
int AsIf(struct ASTNode* Node) {
|
||||||
int FalseLabel, EndLabel;
|
int FalseLabel, EndLabel;
|
||||||
|
|
||||||
FalseLabel = NewLabel();
|
FalseLabel = NewLabel();
|
||||||
if(Node->Right)
|
if (Node->Right)
|
||||||
EndLabel = NewLabel();
|
EndLabel = NewLabel();
|
||||||
|
|
||||||
|
|
||||||
// Left is the condition
|
// Left is the condition
|
||||||
AssembleTree(Node->Left, FalseLabel, Node->Operation);
|
AssembleTree(Node->Left, FalseLabel, Node->Operation);
|
||||||
DeallocateAllRegisters();
|
DeallocateAllRegisters();
|
||||||
|
@ -358,12 +370,12 @@ int AsIf(struct ASTNode* Node) {
|
||||||
DeallocateAllRegisters();
|
DeallocateAllRegisters();
|
||||||
|
|
||||||
// Right is the optional else
|
// Right is the optional else
|
||||||
if(Node->Right)
|
if (Node->Right)
|
||||||
AsJmp(EndLabel);
|
AsJmp(EndLabel);
|
||||||
|
|
||||||
AsLabel(FalseLabel);
|
AsLabel(FalseLabel);
|
||||||
|
|
||||||
if(Node->Right) {
|
if (Node->Right) {
|
||||||
AssembleTree(Node->Right, -1, Node->Operation);
|
AssembleTree(Node->Right, -1, Node->Operation);
|
||||||
DeallocateAllRegisters();
|
DeallocateAllRegisters();
|
||||||
AsLabel(EndLabel);
|
AsLabel(EndLabel);
|
||||||
|
@ -376,9 +388,9 @@ int AsIf(struct ASTNode* Node) {
|
||||||
int AsCompare(int Operation, int RegisterLeft, int RegisterRight) {
|
int AsCompare(int Operation, int RegisterLeft, int RegisterRight) {
|
||||||
printf("Comparing registers %d & %d\n", RegisterLeft, RegisterRight);
|
printf("Comparing registers %d & %d\n", RegisterLeft, RegisterRight);
|
||||||
|
|
||||||
if(Operation < OP_EQUAL || Operation > OP_GREATE)
|
if (Operation < OP_EQUAL || Operation > OP_GREATE)
|
||||||
Die("Bad Operation in AsCompare");
|
Die("Bad Operation in AsCompare");
|
||||||
|
|
||||||
fprintf(OutputFile, "\tcmpq\t%s, %s\n", Registers[RegisterRight], Registers[RegisterLeft]);
|
fprintf(OutputFile, "\tcmpq\t%s, %s\n", Registers[RegisterRight], Registers[RegisterLeft]);
|
||||||
fprintf(OutputFile, "\t%s\t\t%s\n", Comparisons[Operation - OP_EQUAL], ByteRegisters[RegisterRight]);
|
fprintf(OutputFile, "\t%s\t\t%s\n", Comparisons[Operation - OP_EQUAL], ByteRegisters[RegisterRight]);
|
||||||
fprintf(OutputFile, "\tmovzbq\t%s, %s\n", ByteRegisters[RegisterRight], Registers[RegisterLeft]);
|
fprintf(OutputFile, "\tmovzbq\t%s, %s\n", ByteRegisters[RegisterRight], Registers[RegisterLeft]);
|
||||||
|
@ -388,11 +400,12 @@ int AsCompare(int Operation, int RegisterLeft, int RegisterRight) {
|
||||||
|
|
||||||
// Assemble an inverse comparison (a one-line jump)
|
// Assemble an inverse comparison (a one-line jump)
|
||||||
int AsCompareJmp(int Operation, int RegisterLeft, int RegisterRight, int Label) {
|
int AsCompareJmp(int Operation, int RegisterLeft, int RegisterRight, int Label) {
|
||||||
if(Operation < OP_EQUAL || Operation > OP_GREATE)
|
if (Operation < OP_EQUAL || Operation > OP_GREATE)
|
||||||
Die("Bad Operation in AsCompareJmp");
|
Die("Bad Operation in AsCompareJmp");
|
||||||
|
|
||||||
printf("\tBranching on comparison of registers %d & %d, with operation %s\n\n", RegisterLeft, RegisterRight, Comparisons[Operation - OP_EQUAL]);
|
printf("\tBranching on comparison of registers %d & %d, with operation %s\n\n", RegisterLeft, RegisterRight,
|
||||||
|
Comparisons[Operation - OP_EQUAL]);
|
||||||
|
|
||||||
fprintf(OutputFile, "\tcmpq\t%s, %s\n", Registers[RegisterRight], Registers[RegisterLeft]);
|
fprintf(OutputFile, "\tcmpq\t%s, %s\n", Registers[RegisterRight], Registers[RegisterLeft]);
|
||||||
fprintf(OutputFile, "\t%s\tL%d\n", InvComparisons[Operation - OP_EQUAL], Label);
|
fprintf(OutputFile, "\t%s\tL%d\n", InvComparisons[Operation - OP_EQUAL], Label);
|
||||||
DeallocateAllRegisters();
|
DeallocateAllRegisters();
|
||||||
|
@ -424,17 +437,17 @@ int AsNewString(char* Value) {
|
||||||
|
|
||||||
AsLabel(Label);
|
AsLabel(Label);
|
||||||
|
|
||||||
for(CharPtr = Value; *CharPtr; CharPtr++)
|
for (CharPtr = Value; *CharPtr; CharPtr++)
|
||||||
fprintf(OutputFile, "\t.byte\t%d\r\n", *CharPtr);
|
fprintf(OutputFile, "\t.byte\t%d\r\n", *CharPtr);
|
||||||
fprintf(OutputFile, "\t.byte\t0\r\n");
|
fprintf(OutputFile, "\t.byte\t0\r\n");
|
||||||
|
|
||||||
return Label;
|
return Label;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Load a string into a Register.
|
* Load a string into a Register.
|
||||||
* @param ID: the Label number of the string
|
* @param ID: the Label number of the string
|
||||||
*/
|
*/
|
||||||
int AsLoadString(int ID) {
|
int AsLoadString(int ID) {
|
||||||
int Register = RetrieveRegister();
|
int Register = RetrieveRegister();
|
||||||
fprintf(OutputFile, "\tleaq\tL%d(\%%rip), %s\r\n", ID, Registers[Register]);
|
fprintf(OutputFile, "\tleaq\tL%d(\%%rip), %s\r\n", ID, Registers[Register]);
|
||||||
|
@ -444,7 +457,7 @@ int AsLoadString(int ID) {
|
||||||
// Assemble a While loop
|
// Assemble a While loop
|
||||||
int AsWhile(struct ASTNode* Node) {
|
int AsWhile(struct ASTNode* Node) {
|
||||||
int BodyLabel, BreakLabel;
|
int BodyLabel, BreakLabel;
|
||||||
|
|
||||||
BodyLabel = NewLabel();
|
BodyLabel = NewLabel();
|
||||||
BreakLabel = NewLabel();
|
BreakLabel = NewLabel();
|
||||||
|
|
||||||
|
@ -499,7 +512,7 @@ int AsMul(int Left, int Right) {
|
||||||
fprintf(OutputFile, "\timulq\t%s, %s\n", Registers[Left], Registers[Right]);
|
fprintf(OutputFile, "\timulq\t%s, %s\n", Registers[Left], Registers[Right]);
|
||||||
|
|
||||||
DeallocateRegister(Left);
|
DeallocateRegister(Left);
|
||||||
|
|
||||||
return Right;
|
return Right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -537,66 +550,78 @@ int AsShl(int Register, int Val) {
|
||||||
* Load a global variable into a register, with optional pre/post-inc/dec
|
* Load a global variable into a register, with optional pre/post-inc/dec
|
||||||
* @param Entry: The variable to load.
|
* @param Entry: The variable to load.
|
||||||
* @param Operation: An optional SyntaxOps element
|
* @param Operation: An optional SyntaxOps element
|
||||||
*/
|
*/
|
||||||
int AsLdGlobalVar(struct SymbolTableEntry* Entry, int Operation) {
|
int AsLdGlobalVar(struct SymbolTableEntry* Entry, int Operation) {
|
||||||
int Reg = RetrieveRegister();
|
int Reg = RetrieveRegister();
|
||||||
|
|
||||||
printf("\tStoring %s's contents into %s, globally\n", Entry->Name, Registers[Reg]);
|
printf("\tStoring %s's contents into %s, globally\n", Entry->Name, Registers[Reg]);
|
||||||
|
|
||||||
int TypeSize = PrimitiveSize(Entry->Type);
|
int TypeSize = PrimitiveSize(Entry->Type);
|
||||||
switch(TypeSize) {
|
switch (TypeSize) {
|
||||||
case 1:
|
case 1:
|
||||||
switch(Operation) {
|
switch (Operation) {
|
||||||
case OP_PREINC:
|
case OP_PREINC:
|
||||||
fprintf(OutputFile, "\tincb\t%s(\%%rip)\n", Entry->Name); break;
|
fprintf(OutputFile, "\tincb\t%s(\%%rip)\n", Entry->Name);
|
||||||
|
break;
|
||||||
case OP_PREDEC:
|
case OP_PREDEC:
|
||||||
fprintf(OutputFile, "\tdecb\t%s(\%%rip)\n", Entry->Name); break;
|
fprintf(OutputFile, "\tdecb\t%s(\%%rip)\n", Entry->Name);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(OutputFile, "\tmovzbq\t%s(\%%rip), %s\n", Entry->Name, Registers[Reg]);
|
fprintf(OutputFile, "\tmovzbq\t%s(\%%rip), %s\n", Entry->Name, Registers[Reg]);
|
||||||
|
|
||||||
switch(Operation) {
|
switch (Operation) {
|
||||||
case OP_POSTINC:
|
case OP_POSTINC:
|
||||||
fprintf(OutputFile, "\tincb\t%s(\%%rip)\n", Entry->Name); break;
|
fprintf(OutputFile, "\tincb\t%s(\%%rip)\n", Entry->Name);
|
||||||
|
break;
|
||||||
case OP_POSTDEC:
|
case OP_POSTDEC:
|
||||||
fprintf(OutputFile, "\tdecb\t%s(\%%rip)\n", Entry->Name); break;
|
fprintf(OutputFile, "\tdecb\t%s(\%%rip)\n", Entry->Name);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 4:
|
case 4:
|
||||||
switch(Operation) {
|
switch (Operation) {
|
||||||
case OP_PREINC:
|
case OP_PREINC:
|
||||||
fprintf(OutputFile, "\tincl\t%s(\%%rip)\n", Entry->Name); break;
|
fprintf(OutputFile, "\tincl\t%s(\%%rip)\n", Entry->Name);
|
||||||
|
break;
|
||||||
case OP_PREDEC:
|
case OP_PREDEC:
|
||||||
fprintf(OutputFile, "\tdecl\t%s(\%%rip)\n", Entry->Name); break;
|
fprintf(OutputFile, "\tdecl\t%s(\%%rip)\n", Entry->Name);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(OutputFile, "\tmovslq\t%s(\%%rip), %s\n", Entry->Name, Registers[Reg]);
|
fprintf(OutputFile, "\tmovslq\t%s(\%%rip), %s\n", Entry->Name, Registers[Reg]);
|
||||||
|
|
||||||
switch(Operation) {
|
switch (Operation) {
|
||||||
case OP_POSTINC:
|
case OP_POSTINC:
|
||||||
fprintf(OutputFile, "\tincl\t%s(\%%rip)\n", Entry->Name); break;
|
fprintf(OutputFile, "\tincl\t%s(\%%rip)\n", Entry->Name);
|
||||||
|
break;
|
||||||
case OP_POSTDEC:
|
case OP_POSTDEC:
|
||||||
fprintf(OutputFile, "\tdecl\t%s(\%%rip)\n", Entry->Name); break;
|
fprintf(OutputFile, "\tdecl\t%s(\%%rip)\n", Entry->Name);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
switch(Operation) {
|
switch (Operation) {
|
||||||
case OP_PREINC:
|
case OP_PREINC:
|
||||||
fprintf(OutputFile, "\tincq\t%s(\%%rip)\n", Entry->Name); break;
|
fprintf(OutputFile, "\tincq\t%s(\%%rip)\n", Entry->Name);
|
||||||
|
break;
|
||||||
case OP_PREDEC:
|
case OP_PREDEC:
|
||||||
fprintf(OutputFile, "\tdecq\t%s(\%%rip)\n", Entry->Name); break;
|
fprintf(OutputFile, "\tdecq\t%s(\%%rip)\n", Entry->Name);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(OutputFile, "\tmovq\t%s(\%%rip), %s\n", Entry->Name, Registers[Reg]);
|
fprintf(OutputFile, "\tmovq\t%s(\%%rip), %s\n", Entry->Name, Registers[Reg]);
|
||||||
|
|
||||||
switch(Operation) {
|
switch (Operation) {
|
||||||
case OP_POSTINC:
|
case OP_POSTINC:
|
||||||
fprintf(OutputFile, "\tincq\t%s(\%%rip)\n", Entry->Name); break;
|
fprintf(OutputFile, "\tincq\t%s(\%%rip)\n", Entry->Name);
|
||||||
|
break;
|
||||||
case OP_POSTDEC:
|
case OP_POSTDEC:
|
||||||
fprintf(OutputFile, "\tdecq\t%s(\%%rip)\n", Entry->Name); break;
|
fprintf(OutputFile, "\tdecq\t%s(\%%rip)\n", Entry->Name);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -617,16 +642,16 @@ int AsStrGlobalVar(struct SymbolTableEntry* Entry, int Register) {
|
||||||
printf("\tStoring contents of %s into %s, type %d, globally:\n", Registers[Register], Entry->Name, Entry->Type);
|
printf("\tStoring contents of %s into %s, type %d, globally:\n", Registers[Register], Entry->Name, Entry->Type);
|
||||||
|
|
||||||
int TypeSize = PrimitiveSize(Entry->Type);
|
int TypeSize = PrimitiveSize(Entry->Type);
|
||||||
switch(TypeSize) {
|
switch (TypeSize) {
|
||||||
case 1:
|
case 1:
|
||||||
// movzbq zeroes, then moves a byte into the quad register
|
// movzbq zeroes, then moves a byte into the quad register
|
||||||
fprintf(OutputFile, "\tmovb\t%s, %s(\%%rip)\n", ByteRegisters[Register], Entry->Name);
|
fprintf(OutputFile, "\tmovb\t%s, %s(\%%rip)\n", ByteRegisters[Register], Entry->Name);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 4:
|
case 4:
|
||||||
fprintf(OutputFile, "\tmovl\t%s, %s(\%%rip)\n", DoubleRegisters[Register], Entry->Name);
|
fprintf(OutputFile, "\tmovl\t%s, %s(\%%rip)\n", DoubleRegisters[Register], Entry->Name);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 8:
|
case 8:
|
||||||
fprintf(OutputFile, "\tmovq\t%s, %s(%%rip)\n", Registers[Register], Entry->Name);
|
fprintf(OutputFile, "\tmovq\t%s, %s(%%rip)\n", Registers[Register], Entry->Name);
|
||||||
break;
|
break;
|
||||||
|
@ -634,7 +659,7 @@ int AsStrGlobalVar(struct SymbolTableEntry* Entry, int Register) {
|
||||||
default:
|
default:
|
||||||
DieMessage("Bad type for saving", TypeNames(Entry->Type));
|
DieMessage("Bad type for saving", TypeNames(Entry->Type));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Register;
|
return Register;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -648,61 +673,73 @@ int AsLdLocalVar(struct SymbolTableEntry* Entry, int Operation) {
|
||||||
int Reg = RetrieveRegister();
|
int Reg = RetrieveRegister();
|
||||||
|
|
||||||
printf("\tStoring the var at %d's contents into %s, locally\n", Entry->SinkOffset, Registers[Reg]);
|
printf("\tStoring the var at %d's contents into %s, locally\n", Entry->SinkOffset, Registers[Reg]);
|
||||||
|
|
||||||
int TypeSize = PrimitiveSize(Entry->Type);
|
int TypeSize = PrimitiveSize(Entry->Type);
|
||||||
switch(TypeSize) {
|
switch (TypeSize) {
|
||||||
case 1:
|
case 1:
|
||||||
switch(Operation) {
|
switch (Operation) {
|
||||||
case OP_PREINC:
|
case OP_PREINC:
|
||||||
fprintf(OutputFile, "\tincb\t%d(\%%rbp)\n", Entry->SinkOffset); break;
|
fprintf(OutputFile, "\tincb\t%d(\%%rbp)\n", Entry->SinkOffset);
|
||||||
|
break;
|
||||||
case OP_PREDEC:
|
case OP_PREDEC:
|
||||||
fprintf(OutputFile, "\tdecb\t%d(\%%rbp)\n", Entry->SinkOffset); break;
|
fprintf(OutputFile, "\tdecb\t%d(\%%rbp)\n", Entry->SinkOffset);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(OutputFile, "\tmovzbq\t%d(\%%rbp), %s\n", Entry->SinkOffset, Registers[Reg]);
|
fprintf(OutputFile, "\tmovzbq\t%d(\%%rbp), %s\n", Entry->SinkOffset, Registers[Reg]);
|
||||||
|
|
||||||
switch(Operation) {
|
switch (Operation) {
|
||||||
case OP_POSTINC:
|
case OP_POSTINC:
|
||||||
fprintf(OutputFile, "\tincb\t%d(\%%rbp)\n", Entry->SinkOffset); break;
|
fprintf(OutputFile, "\tincb\t%d(\%%rbp)\n", Entry->SinkOffset);
|
||||||
|
break;
|
||||||
case OP_POSTDEC:
|
case OP_POSTDEC:
|
||||||
fprintf(OutputFile, "\tdecb\t%d(\%%rbp)\n", Entry->SinkOffset); break;
|
fprintf(OutputFile, "\tdecb\t%d(\%%rbp)\n", Entry->SinkOffset);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 4:
|
case 4:
|
||||||
switch(Operation) {
|
switch (Operation) {
|
||||||
case OP_PREINC:
|
case OP_PREINC:
|
||||||
fprintf(OutputFile, "\tincl\t%d(\%%rbp)\n", Entry->SinkOffset); break;
|
fprintf(OutputFile, "\tincl\t%d(\%%rbp)\n", Entry->SinkOffset);
|
||||||
|
break;
|
||||||
case OP_PREDEC:
|
case OP_PREDEC:
|
||||||
fprintf(OutputFile, "\tdecl\t%d(\%%rbp)\n", Entry->SinkOffset); break;
|
fprintf(OutputFile, "\tdecl\t%d(\%%rbp)\n", Entry->SinkOffset);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(OutputFile, "\tmovslq\t%d(\%%rbp), %s\n", Entry->SinkOffset, Registers[Reg]);
|
fprintf(OutputFile, "\tmovslq\t%d(\%%rbp), %s\n", Entry->SinkOffset, Registers[Reg]);
|
||||||
|
|
||||||
switch(Operation) {
|
switch (Operation) {
|
||||||
case OP_POSTINC:
|
case OP_POSTINC:
|
||||||
fprintf(OutputFile, "\tincl\t%d(\%%rbp)\n", Entry->SinkOffset); break;
|
fprintf(OutputFile, "\tincl\t%d(\%%rbp)\n", Entry->SinkOffset);
|
||||||
|
break;
|
||||||
case OP_POSTDEC:
|
case OP_POSTDEC:
|
||||||
fprintf(OutputFile, "\tdecl\t%d(\%%rbp)\n", Entry->SinkOffset); break;
|
fprintf(OutputFile, "\tdecl\t%d(\%%rbp)\n", Entry->SinkOffset);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
switch(Operation) {
|
switch (Operation) {
|
||||||
case OP_PREINC:
|
case OP_PREINC:
|
||||||
fprintf(OutputFile, "\tincq\t%d(\%%rbp)\n", Entry->SinkOffset); break;
|
fprintf(OutputFile, "\tincq\t%d(\%%rbp)\n", Entry->SinkOffset);
|
||||||
|
break;
|
||||||
case OP_PREDEC:
|
case OP_PREDEC:
|
||||||
fprintf(OutputFile, "\tdecq\t%d(\%%rbp)\n", Entry->SinkOffset); break;
|
fprintf(OutputFile, "\tdecq\t%d(\%%rbp)\n", Entry->SinkOffset);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(OutputFile, "\tmovq\t%d(\%%rbp), %s\n", Entry->SinkOffset, Registers[Reg]);
|
fprintf(OutputFile, "\tmovq\t%d(\%%rbp), %s\n", Entry->SinkOffset, Registers[Reg]);
|
||||||
|
|
||||||
switch(Operation) {
|
switch (Operation) {
|
||||||
case OP_POSTINC:
|
case OP_POSTINC:
|
||||||
fprintf(OutputFile, "\tincq\t%d(\%%rbp)\n", Entry->SinkOffset); break;
|
fprintf(OutputFile, "\tincq\t%d(\%%rbp)\n", Entry->SinkOffset);
|
||||||
|
break;
|
||||||
case OP_POSTDEC:
|
case OP_POSTDEC:
|
||||||
fprintf(OutputFile, "\tdecq\t%d(\%%rbp)\n", Entry->SinkOffset); break;
|
fprintf(OutputFile, "\tdecq\t%d(\%%rbp)\n", Entry->SinkOffset);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -713,7 +750,7 @@ int AsLdLocalVar(struct SymbolTableEntry* Entry, int Operation) {
|
||||||
|
|
||||||
return Reg;
|
return Reg;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Store a value from a register into a local variable.
|
* Store a value from a register into a local variable.
|
||||||
* @param Entry: The local variable to write to.
|
* @param Entry: The local variable to write to.
|
||||||
|
@ -724,16 +761,16 @@ int AsStrLocalVar(struct SymbolTableEntry* Entry, int Register) {
|
||||||
printf("\tStoring contents of %s into %s, type %d, locally\n", Registers[Register], Entry->Name, Entry->Type);
|
printf("\tStoring contents of %s into %s, type %d, locally\n", Registers[Register], Entry->Name, Entry->Type);
|
||||||
|
|
||||||
int TypeSize = PrimitiveSize(Entry->Type);
|
int TypeSize = PrimitiveSize(Entry->Type);
|
||||||
switch(TypeSize) {
|
switch (TypeSize) {
|
||||||
case 1:
|
case 1:
|
||||||
// movzbq zeroes, then moves a byte into the quad register
|
// movzbq zeroes, then moves a byte into the quad register
|
||||||
fprintf(OutputFile, "\tmovb\t%s, %d(\%%rbp)\n", ByteRegisters[Register], Entry->SinkOffset);
|
fprintf(OutputFile, "\tmovb\t%s, %d(\%%rbp)\n", ByteRegisters[Register], Entry->SinkOffset);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 4:
|
case 4:
|
||||||
fprintf(OutputFile, "\tmovl\t%s, %d(\%%rbp)\n", DoubleRegisters[Register], Entry->SinkOffset);
|
fprintf(OutputFile, "\tmovl\t%s, %d(\%%rbp)\n", DoubleRegisters[Register], Entry->SinkOffset);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 8:
|
case 8:
|
||||||
fprintf(OutputFile, "\tmovq\t%s, %d(%%rbp)\n", Registers[Register], Entry->SinkOffset);
|
fprintf(OutputFile, "\tmovq\t%s, %d(%%rbp)\n", Registers[Register], Entry->SinkOffset);
|
||||||
break;
|
break;
|
||||||
|
@ -741,7 +778,7 @@ int AsStrLocalVar(struct SymbolTableEntry* Entry, int Register) {
|
||||||
default:
|
default:
|
||||||
DieMessage("Bad type for saving", TypeNames(Entry->Type));
|
DieMessage("Bad type for saving", TypeNames(Entry->Type));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Register;
|
return Register;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -760,17 +797,20 @@ int AsDeref(int Reg, int Type) {
|
||||||
int DestSize = PrimitiveSize(ValueAt(Type));
|
int DestSize = PrimitiveSize(ValueAt(Type));
|
||||||
|
|
||||||
printf("\tDereferencing %s\n", Registers[Reg]);
|
printf("\tDereferencing %s\n", Registers[Reg]);
|
||||||
switch(DestSize) {
|
switch (DestSize) {
|
||||||
case 1:
|
case 1:
|
||||||
fprintf(OutputFile, "\tmovzbq\t(%s), %s\n", Registers[Reg], Registers[Reg]);
|
fprintf(OutputFile, "\tmovzbq\t(%s), %s\n", Registers[Reg], ByteRegisters[Reg]);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
fprintf(OutputFile, "\tmovslq\t(%s), %s\n", Registers[Reg], Registers[Reg]);
|
fprintf(OutputFile, "\tmovslq\t(%s), %s\n", Registers[Reg], DoubleRegisters[Reg]);
|
||||||
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
|
fprintf(OutputFile, "\tmovl\t(%s), %s\n", Registers[Reg], DoubleRegisters[Reg]);
|
||||||
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
fprintf(OutputFile, "\tmovq\t(%s), %s\n", Registers[Reg], Registers[Reg]);
|
fprintf(OutputFile, "\tmovq\t(%s), %s\n", Registers[Reg], Registers[Reg]);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
DieDecimal("Can't generate dereference for type", Type);
|
DieDecimal("Can't generate dereference for type", Type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -779,13 +819,16 @@ int AsDeref(int Reg, int Type) {
|
||||||
|
|
||||||
// Assemble a store-through-dereference
|
// Assemble a store-through-dereference
|
||||||
int AsStrDeref(int Register1, int Register2, int Type) {
|
int AsStrDeref(int Register1, int Register2, int Type) {
|
||||||
printf("\tStoring contents of %s into %s through a dereference, type %d\n", Registers[Register1], Registers[Register2], Type);
|
printf("\tStoring contents of %s into %s through a dereference, type %d\n", Registers[Register1],
|
||||||
|
Registers[Register2], Type);
|
||||||
|
|
||||||
switch(Type) {
|
switch (Type) {
|
||||||
case RET_CHAR:
|
case RET_CHAR:
|
||||||
fprintf(OutputFile, "\tmovb\t%s, (%s)\n", ByteRegisters[Register1], Registers[Register2]);
|
fprintf(OutputFile, "\tmovb\t%s, (%s)\n", ByteRegisters[Register1], Registers[Register2]);
|
||||||
break;
|
break;
|
||||||
case RET_INT:
|
case RET_INT:
|
||||||
|
fprintf(OutputFile, "\tmovl\t%s, (%s)\n", DoubleRegisters[Register1], Registers[Register2]);
|
||||||
|
break;
|
||||||
case RET_LONG:
|
case RET_LONG:
|
||||||
fprintf(OutputFile, "\tmovq\t%s, (%s)\n", Registers[Register1], Registers[Register2]);
|
fprintf(OutputFile, "\tmovq\t%s, (%s)\n", Registers[Register1], Registers[Register2]);
|
||||||
break;
|
break;
|
||||||
|
@ -799,27 +842,33 @@ int AsStrDeref(int Register1, int Register2, int Type) {
|
||||||
// Assemble a global symbol (variable, struct, enum, function, string)
|
// Assemble a global symbol (variable, struct, enum, function, string)
|
||||||
void AsGlobalSymbol(struct SymbolTableEntry* Entry) {
|
void AsGlobalSymbol(struct SymbolTableEntry* Entry) {
|
||||||
|
|
||||||
if(Entry == NULL) return;
|
if (Entry == NULL) return;
|
||||||
if(Entry->Structure == ST_FUNC) return;
|
if (Entry->Structure == ST_FUNC) return;
|
||||||
|
|
||||||
|
|
||||||
int Size = TypeSize(Entry->Type, Entry->CompositeType);
|
int Size = TypeSize(Entry->Type, Entry->CompositeType);
|
||||||
|
|
||||||
fprintf(OutputFile, "\t.data\n"
|
fprintf(OutputFile, "\t.data\n"
|
||||||
"\t.globl\t%s\n",
|
"\t.globl\t%s\n",
|
||||||
Entry->Name);
|
Entry->Name);
|
||||||
|
|
||||||
fprintf(OutputFile, "%s:\n", Entry->Name);
|
fprintf(OutputFile, "%s:\n", Entry->Name);
|
||||||
|
|
||||||
switch(Size) {
|
switch (Size) {
|
||||||
case 1: fprintf(OutputFile, "\t.byte\t0\r\n", Entry->Name); break;
|
case 1:
|
||||||
case 4: fprintf(OutputFile, "\t.long\t0\r\n", Entry->Name); break;
|
fprintf(OutputFile, "\t.byte\t0\r\n", Entry->Name);
|
||||||
case 8: fprintf(OutputFile, "\t.quad\t0\r\n", Entry->Name); break;
|
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:
|
default:
|
||||||
for(int i = 0; i < Size; i++)
|
for (int i = 0; i < Size; i++)
|
||||||
fprintf(OutputFile, "\t.byte\t0\n");
|
fprintf(OutputFile, "\t.byte\t0\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assemble a function call, with all associated parameter bumping and stack movement.
|
// Assemble a function call, with all associated parameter bumping and stack movement.
|
||||||
|
@ -827,10 +876,10 @@ int AsCallWrapper(struct ASTNode* Node) {
|
||||||
struct ASTNode* CompositeTree = Node->Left;
|
struct ASTNode* CompositeTree = Node->Left;
|
||||||
int Register, Args = 0;
|
int Register, Args = 0;
|
||||||
|
|
||||||
while(CompositeTree) {
|
while (CompositeTree) {
|
||||||
Register = AssembleTree(CompositeTree->Right, -1, CompositeTree->Operation);
|
Register = AssembleTree(CompositeTree->Right, -1, CompositeTree->Operation);
|
||||||
AsCopyArgs(Register, CompositeTree->Size);
|
AsCopyArgs(Register, CompositeTree->Size);
|
||||||
if(Args == 0) Args = CompositeTree->Size;
|
if (Args == 0) Args = CompositeTree->Size;
|
||||||
DeallocateAllRegisters();
|
DeallocateAllRegisters();
|
||||||
CompositeTree = CompositeTree->Left;
|
CompositeTree = CompositeTree->Left;
|
||||||
}
|
}
|
||||||
|
@ -840,10 +889,10 @@ int AsCallWrapper(struct ASTNode* Node) {
|
||||||
|
|
||||||
// Copy a function argument from Register to argument Position
|
// Copy a function argument from Register to argument Position
|
||||||
void AsCopyArgs(int Register, int Position) {
|
void AsCopyArgs(int Register, int Position) {
|
||||||
if(Position > 4) { // Args above 4 go on the stack
|
if (Position > 4) { // Args above 4 go on the stack
|
||||||
fprintf(OutputFile, "\tpushq\t%s\n", Registers[Register]);
|
fprintf(OutputFile, "\tpushq\t%s\n", Registers[Register]);
|
||||||
} else {
|
} else {
|
||||||
fprintf(OutputFile, "\tmovq\t%s, %s\n", Registers[Register], Registers[10 - Position]);
|
fprintf(OutputFile, "\tmovq\t%s, %s\n", Registers[Register], Registers[8 - Position]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -857,11 +906,11 @@ int AsCall(struct SymbolTableEntry* Entry, int Args) {
|
||||||
printf("\t\t\tFunction returns into %s\n", Registers[OutRegister]);
|
printf("\t\t\tFunction returns into %s\n", Registers[OutRegister]);
|
||||||
|
|
||||||
fprintf(OutputFile, "\tcall\t%s\n", Entry->Name);
|
fprintf(OutputFile, "\tcall\t%s\n", Entry->Name);
|
||||||
if(Args > 4)
|
if (Args > 4)
|
||||||
fprintf(OutputFile, "\taddq\t$%d, %%rsp\n", 8 * (Args - 4));
|
fprintf(OutputFile, "\taddq\t$%d, %%rsp\n", 8 * (Args - 4));
|
||||||
|
|
||||||
fprintf(OutputFile, "\tmovq\t%%rax, %s\n", Registers[OutRegister]);
|
fprintf(OutputFile, "\tmovq\t%%rax, %s\n", Registers[OutRegister]);
|
||||||
|
|
||||||
return OutRegister;
|
return OutRegister;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -870,19 +919,19 @@ int AsReturn(struct SymbolTableEntry* Entry, int Register) {
|
||||||
|
|
||||||
printf("\t\tCreating return for function %s\n", Entry->Name);
|
printf("\t\tCreating return for function %s\n", Entry->Name);
|
||||||
|
|
||||||
switch(Entry->Type) {
|
switch (Entry->Type) {
|
||||||
case RET_CHAR:
|
case RET_CHAR:
|
||||||
fprintf(OutputFile, "\tmovzbl\t%s, %%eax\n", ByteRegisters[Register]);
|
fprintf(OutputFile, "\tmovzbl\t%s, %%eax\n", ByteRegisters[Register]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RET_INT:
|
case RET_INT:
|
||||||
fprintf(OutputFile, "\tmovl\t%s, %%eax\n", DoubleRegisters[Register]);
|
fprintf(OutputFile, "\tmovl\t%s, %%eax\n", DoubleRegisters[Register]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RET_LONG:
|
case RET_LONG:
|
||||||
fprintf(OutputFile, "\tmovq\t%s, %%rax\n", Registers[Register]);
|
fprintf(OutputFile, "\tmovq\t%s, %%rax\n", Registers[Register]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
DieMessage("Bad function type in generating return", TypeNames(Entry->Type));
|
DieMessage("Bad function type in generating return", TypeNames(Entry->Type));
|
||||||
|
|
||||||
|
@ -1001,7 +1050,7 @@ int AsShiftRight(int Left, int Right) {
|
||||||
int AsBooleanConvert(int Register, int Operation, int Label) {
|
int AsBooleanConvert(int Register, int Operation, int Label) {
|
||||||
fprintf(OutputFile, "\ttest\t%s, %s\n", Registers[Register], Registers[Register]);
|
fprintf(OutputFile, "\ttest\t%s, %s\n", Registers[Register], Registers[Register]);
|
||||||
|
|
||||||
switch(Operation) {
|
switch (Operation) {
|
||||||
case OP_IF:
|
case OP_IF:
|
||||||
case OP_LOOP:
|
case OP_LOOP:
|
||||||
fprintf(OutputFile, "\tje\tL%d\n", Label);
|
fprintf(OutputFile, "\tje\tL%d\n", Label);
|
||||||
|
@ -1036,7 +1085,7 @@ void AssemblerPreamble() {
|
||||||
*/
|
*/
|
||||||
void AsFunctionPreamble(struct SymbolTableEntry* Entry) {
|
void AsFunctionPreamble(struct SymbolTableEntry* Entry) {
|
||||||
char* Name = Entry->Name;
|
char* Name = Entry->Name;
|
||||||
struct SymbolTableEntry* Param, *Local;
|
struct SymbolTableEntry* Param, * Local;
|
||||||
int ParamOffset = 0, ParamReg = 9, ParamCount = 0;
|
int ParamOffset = 0, ParamReg = 9, ParamCount = 0;
|
||||||
|
|
||||||
LocalVarOffset = 4; // Prepare parameters
|
LocalVarOffset = 4; // Prepare parameters
|
||||||
|
@ -1049,17 +1098,17 @@ void AsFunctionPreamble(struct SymbolTableEntry* Entry) {
|
||||||
"\tpushq\t%%rbp\n"
|
"\tpushq\t%%rbp\n"
|
||||||
"\tmovq\t%%rsp, %%rbp\r\n",
|
"\tmovq\t%%rsp, %%rbp\r\n",
|
||||||
Name, Name, Name);
|
Name, Name, Name);
|
||||||
|
|
||||||
//PECOFF requires we call the global initialisers
|
//PECOFF requires we call the global initialisers
|
||||||
if(!strcmp(Name, "main"))
|
if (!strcmp(Name, "main"))
|
||||||
fprintf(OutputFile, "\tcall\t__main\n");
|
fprintf(OutputFile, "\tcall\t__main\n");
|
||||||
|
|
||||||
// Need to share this between two loops. Fun.
|
// Need to share this between two loops. Fun.
|
||||||
int LoopIndex;
|
int LoopIndex;
|
||||||
|
|
||||||
// If we have parameters, move them to the last 4 registers
|
// If we have parameters, move them to the last 4 registers
|
||||||
for(Param = Entry->Start, ParamCount = 1; Param != NULL; Param = Param->NextSymbol, ParamCount++) {
|
for (Param = Entry->Start, ParamCount = 1; Param != NULL; Param = Param->NextSymbol, ParamCount++) {
|
||||||
if(ParamCount > 4) { // We only have 4 argument registers
|
if (ParamCount > 4) { // We only have 4 argument registers
|
||||||
Param->SinkOffset = ParamOffset;
|
Param->SinkOffset = ParamOffset;
|
||||||
ParamOffset += 8;
|
ParamOffset += 8;
|
||||||
}
|
}
|
||||||
|
@ -1069,13 +1118,13 @@ void AsFunctionPreamble(struct SymbolTableEntry* Entry) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we have more parameters, move them to the stack
|
// If we have more parameters, move them to the stack
|
||||||
for(Local = Locals; Local != NULL; Local = Local->NextSymbol) {
|
for (Local = Locals; Local != NULL; Local = Local->NextSymbol) {
|
||||||
Local->SinkOffset = AsCalcOffset(Local->Type);
|
Local->SinkOffset = AsCalcOffset(Local->Type);
|
||||||
}
|
}
|
||||||
|
|
||||||
// With all the parameters on the stack, we can allocate the shadow space
|
// With all the parameters on the stack, we can allocate the shadow space
|
||||||
StackFrameOffset = ((LocalVarOffset + 31) & ~31);
|
StackFrameOffset = ((LocalVarOffset + 31) & ~31);
|
||||||
fprintf(OutputFile,
|
fprintf(OutputFile,
|
||||||
"\taddq\t$%d, %%rsp\n", -StackFrameOffset);
|
"\taddq\t$%d, %%rsp\n", -StackFrameOffset);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,19 +31,19 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
char* Suffixate(char* String, char Suffix) {
|
char* Suffixate(char* String, char Suffix) {
|
||||||
char* Pos, *NewStr;
|
char* Pos, * NewStr;
|
||||||
|
|
||||||
if((NewStr = strdup(String)) == NULL)
|
if ((NewStr = strdup(String)) == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if((Pos = strrchr(NewStr, '.')) == NULL)
|
if ((Pos = strrchr(NewStr, '.')) == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
Pos++;
|
Pos++;
|
||||||
|
|
||||||
if(*Pos == '\0')
|
if (*Pos == '\0')
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
*Pos++ = Suffix;
|
*Pos++ = Suffix;
|
||||||
*Pos = '\0';
|
*Pos = '\0';
|
||||||
return NewStr;
|
return NewStr;
|
||||||
|
@ -68,17 +68,17 @@ char* Suffixate(char* String, char Suffix) {
|
||||||
char* Compile(char* InputFile) {
|
char* Compile(char* InputFile) {
|
||||||
char* OutputName;
|
char* OutputName;
|
||||||
OutputName = Suffixate(InputFile, 's');
|
OutputName = Suffixate(InputFile, 's');
|
||||||
if(OutputName == NULL) {
|
if (OutputName == NULL) {
|
||||||
fprintf(stderr, "%s must have a suffix.\r\n", InputFile);
|
fprintf(stderr, "%s must have a suffix.\r\n", InputFile);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if((SourceFile = fopen(InputFile, "r")) == NULL) {
|
if ((SourceFile = fopen(InputFile, "r")) == NULL) {
|
||||||
fprintf(stderr, "Unable to open %s: %s\n", InputFile, strerror(errno));
|
fprintf(stderr, "Unable to open %s: %s\n", InputFile, strerror(errno));
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if((OutputFile = fopen(OutputName, "w")) == NULL) {
|
if ((OutputFile = fopen(OutputName, "w")) == NULL) {
|
||||||
fprintf(stderr, "Unable to open %s: %s\n", OutputName, strerror(errno));
|
fprintf(stderr, "Unable to open %s: %s\n", OutputName, strerror(errno));
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
@ -88,9 +88,9 @@ char* Compile(char* InputFile) {
|
||||||
CurrentGlobal = 0;
|
CurrentGlobal = 0;
|
||||||
CurrentLocal = SYMBOLS - 1;
|
CurrentLocal = SYMBOLS - 1;
|
||||||
|
|
||||||
if(OptVerboseOutput)
|
if (OptVerboseOutput)
|
||||||
printf("Compiling %s\r\n", InputFile);
|
printf("Compiling %s\r\n", InputFile);
|
||||||
|
|
||||||
Tokenise();
|
Tokenise();
|
||||||
|
|
||||||
AssemblerPreamble();
|
AssemblerPreamble();
|
||||||
|
@ -120,18 +120,18 @@ char* Assemble(char* InputFile) {
|
||||||
int Error;
|
int Error;
|
||||||
char* OutputName;
|
char* OutputName;
|
||||||
OutputName = Suffixate(InputFile, 'o');
|
OutputName = Suffixate(InputFile, 'o');
|
||||||
if(OutputName == NULL) {
|
if (OutputName == NULL) {
|
||||||
fprintf(stderr, "%s must have a suffix.\r\n", InputFile);
|
fprintf(stderr, "%s must have a suffix.\r\n", InputFile);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(Command, TEXTLEN, "%s %s %s", "as -o ", OutputName, InputFile);
|
snprintf(Command, TEXTLEN, "%s %s %s", "as -o ", OutputName, InputFile);
|
||||||
if(OptVerboseOutput)
|
if (OptVerboseOutput)
|
||||||
printf("%s\n", Command);
|
printf("%s\n", Command);
|
||||||
|
|
||||||
Error = system(Command);
|
Error = system(Command);
|
||||||
|
|
||||||
if(Error != 0) {
|
if (Error != 0) {
|
||||||
fprintf(stderr, "Assembling of %s failed with code %d\n", InputFile, Error);
|
fprintf(stderr, "Assembling of %s failed with code %d\n", InputFile, Error);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
@ -152,26 +152,26 @@ char* Assemble(char* InputFile) {
|
||||||
|
|
||||||
void Link(char* Output, char* Objects[]) {
|
void Link(char* Output, char* Objects[]) {
|
||||||
int Count, Size = TEXTLEN, Error;
|
int Count, Size = TEXTLEN, Error;
|
||||||
char Command[TEXTLEN], *CommandPtr;
|
char Command[TEXTLEN], * CommandPtr;
|
||||||
|
|
||||||
CommandPtr = Command;
|
CommandPtr = Command;
|
||||||
Count = snprintf(CommandPtr, Size, "%s %s ", "gcc -o ", OutputFileName);
|
Count = snprintf(CommandPtr, Size, "%s %s ", "gcc -o ", OutputFileName);
|
||||||
CommandPtr += Count;
|
CommandPtr += Count;
|
||||||
Size -= Count;
|
Size -= Count;
|
||||||
|
|
||||||
while(*Objects != NULL) {
|
while (*Objects != NULL) {
|
||||||
Count = snprintf(CommandPtr, Size, "%s ", *Objects);
|
Count = snprintf(CommandPtr, Size, "%s ", *Objects);
|
||||||
CommandPtr += Count;
|
CommandPtr += Count;
|
||||||
Size -= Count;
|
Size -= Count;
|
||||||
Objects++;
|
Objects++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(OptVerboseOutput)
|
if (OptVerboseOutput)
|
||||||
printf("%s\n", Command);
|
printf("%s\n", Command);
|
||||||
|
|
||||||
Error = system(Command);
|
Error = system(Command);
|
||||||
|
|
||||||
if(Error != 0) {
|
if (Error != 0) {
|
||||||
fprintf(stderr, "Link failure\n");
|
fprintf(stderr, "Link failure\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
187
src/Dump.c
187
src/Dump.c
|
@ -19,13 +19,13 @@ void DumpTree(struct ASTNode* Node, int level) {
|
||||||
int Lfalse, Lstart, Lend;
|
int Lfalse, Lstart, Lend;
|
||||||
|
|
||||||
// Handle weirdo loops and conditions first.
|
// Handle weirdo loops and conditions first.
|
||||||
switch(Node->Operation) {
|
switch (Node->Operation) {
|
||||||
case OP_IF:
|
case OP_IF:
|
||||||
Lfalse = GenerateSrg();
|
Lfalse = GenerateSrg();
|
||||||
for(int i = 0; i < level; i++)
|
for (int i = 0; i < level; i++)
|
||||||
fprintf(stdout, " ");
|
fprintf(stdout, " ");
|
||||||
fprintf(stdout, "IF");
|
fprintf(stdout, "IF");
|
||||||
if(Node->Right) {
|
if (Node->Right) {
|
||||||
Lend = GenerateSrg();
|
Lend = GenerateSrg();
|
||||||
fprintf(stdout, ", end label %d", Lend);
|
fprintf(stdout, ", end label %d", Lend);
|
||||||
}
|
}
|
||||||
|
@ -33,14 +33,14 @@ void DumpTree(struct ASTNode* Node, int level) {
|
||||||
fprintf(stdout, "\n");
|
fprintf(stdout, "\n");
|
||||||
DumpTree(Node->Left, level + 2);
|
DumpTree(Node->Left, level + 2);
|
||||||
DumpTree(Node->Middle, level + 2);
|
DumpTree(Node->Middle, level + 2);
|
||||||
|
|
||||||
if(Node->Right)
|
if (Node->Right)
|
||||||
DumpTree(Node->Right, level + 2);
|
DumpTree(Node->Right, level + 2);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
case OP_LOOP:
|
case OP_LOOP:
|
||||||
Lstart = GenerateSrg();
|
Lstart = GenerateSrg();
|
||||||
for(int i = 0; i < level; i++)
|
for (int i = 0; i < level; i++)
|
||||||
fprintf(stdout, " ");
|
fprintf(stdout, " ");
|
||||||
fprintf(stdout, "LOOP starts at %d\n", Lstart);
|
fprintf(stdout, "LOOP starts at %d\n", Lstart);
|
||||||
Lend = GenerateSrg();
|
Lend = GenerateSrg();
|
||||||
|
@ -50,68 +50,139 @@ void DumpTree(struct ASTNode* Node, int level) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// If current node is a compound, we treat it as if we didn't just enter a loop.
|
// 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;
|
level = -2;
|
||||||
|
|
||||||
if(Node->Left)
|
if (Node->Left)
|
||||||
DumpTree(Node->Left, level + 2);
|
DumpTree(Node->Left, level + 2);
|
||||||
|
|
||||||
if(Node->Right)
|
if (Node->Right)
|
||||||
DumpTree(Node->Right, level + 2);
|
DumpTree(Node->Right, level + 2);
|
||||||
|
|
||||||
// The meat of this operation!
|
// The meat of this operation!
|
||||||
for(int i = 0; i < level; i++)
|
for (int i = 0; i < level; i++)
|
||||||
fprintf(stdout, " ");
|
fprintf(stdout, " ");
|
||||||
|
|
||||||
switch (Node->Operation){
|
switch (Node->Operation) {
|
||||||
case OP_COMP: fprintf(stdout, "\n\n"); return;
|
case OP_COMP:
|
||||||
case OP_FUNC: fprintf(stdout, "OP_FUNC %s\n", Node->Symbol->Name); return;
|
fprintf(stdout, "\n\n");
|
||||||
case OP_ADD: fprintf(stdout, "OP_ADD\n"); return;
|
return;
|
||||||
case OP_SUBTRACT: fprintf(stdout, "OP_SUBTRACT\n"); return;
|
case OP_FUNC:
|
||||||
case OP_MULTIPLY: fprintf(stdout, "OP_MULTIPLY\n"); return;
|
fprintf(stdout, "OP_FUNC %s\n", Node->Symbol->Name);
|
||||||
case OP_DIVIDE: fprintf(stdout, "OP_DIVIDE\n"); return;
|
return;
|
||||||
case OP_EQUAL: fprintf(stdout, "OP_EQUAL\n"); return;
|
case OP_ADD:
|
||||||
case OP_INEQ: fprintf(stdout, "OP_INEQ\n"); return;
|
fprintf(stdout, "OP_ADD\n");
|
||||||
case OP_LESS: fprintf(stdout, "OP_LESS\n"); return;
|
return;
|
||||||
case OP_GREAT: fprintf(stdout, "OP_GREAT\n"); return;
|
case OP_SUBTRACT:
|
||||||
case OP_LESSE: fprintf(stdout, "OP_LESSE\n"); return;
|
fprintf(stdout, "OP_SUBTRACT\n");
|
||||||
case OP_GREATE: fprintf(stdout, "OP_GREATE\n"); return;
|
return;
|
||||||
case TERM_INTLITERAL: fprintf(stdout, "TERM_INTLITERAL %d\n", Node->IntValue); return;
|
case OP_MULTIPLY:
|
||||||
case TERM_STRLITERAL: fprintf(stdout, "TERM_STRLITERAL rval L%d\n", Node->IntValue); return;
|
fprintf(stdout, "OP_MULTIPLY\n");
|
||||||
case REF_IDENT:
|
return;
|
||||||
if(Node->RVal)
|
case OP_DIVIDE:
|
||||||
fprintf(stdout, "REF_IDENT rval %s\n", Node->Symbol->Name);
|
fprintf(stdout, "OP_DIVIDE\n");
|
||||||
else
|
return;
|
||||||
fprintf(stdout, "REF_IDENT %s\n", Node->Symbol->Name);
|
case OP_EQUAL:
|
||||||
|
fprintf(stdout, "OP_EQUAL\n");
|
||||||
|
return;
|
||||||
|
case OP_INEQ:
|
||||||
|
fprintf(stdout, "OP_INEQ\n");
|
||||||
|
return;
|
||||||
|
case OP_LESS:
|
||||||
|
fprintf(stdout, "OP_LESS\n");
|
||||||
|
return;
|
||||||
|
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->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", Node->Symbol->Name);
|
||||||
|
else
|
||||||
|
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", 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->Size));
|
||||||
return;
|
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", 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->Size)); return;
|
|
||||||
|
|
||||||
case OP_BOOLOR: fprintf(stdout, "OP_BOOLOR\n"); return;
|
case OP_BOOLOR:
|
||||||
case OP_BOOLAND: fprintf(stdout, "OP_BOOLAND\n"); return;
|
fprintf(stdout, "OP_BOOLOR\n");
|
||||||
case OP_BITOR: fprintf(stdout, "OP_BITOR\n"); return;
|
return;
|
||||||
case OP_BITXOR: fprintf(stdout, "OP_BITXOR\n"); return;
|
case OP_BOOLAND:
|
||||||
case OP_BITAND: fprintf(stdout, "OP_BITAND\n"); return;
|
fprintf(stdout, "OP_BOOLAND\n");
|
||||||
|
return;
|
||||||
|
case OP_BITOR:
|
||||||
|
fprintf(stdout, "OP_BITOR\n");
|
||||||
|
return;
|
||||||
|
case OP_BITXOR:
|
||||||
|
fprintf(stdout, "OP_BITXOR\n");
|
||||||
|
return;
|
||||||
|
case OP_BITAND:
|
||||||
|
fprintf(stdout, "OP_BITAND\n");
|
||||||
|
return;
|
||||||
|
|
||||||
case OP_SHIFTL: fprintf(stdout, "OP_SHIFTL\n"); return;
|
case OP_SHIFTL:
|
||||||
case OP_SHIFTR: fprintf(stdout, "OP_SHIFTR\n"); return;
|
fprintf(stdout, "OP_SHIFTL\n");
|
||||||
|
return;
|
||||||
|
case OP_SHIFTR:
|
||||||
|
fprintf(stdout, "OP_SHIFTR\n");
|
||||||
|
return;
|
||||||
|
|
||||||
case OP_PREINC: fprintf(stdout, "OP_PREINC\n"); return;
|
case OP_PREINC:
|
||||||
case OP_PREDEC: fprintf(stdout, "OP_PREDEC\n"); return;
|
fprintf(stdout, "OP_PREINC\n");
|
||||||
case OP_POSTINC: fprintf(stdout, "OP_POSTINC\n"); return;
|
return;
|
||||||
case OP_POSTDEC: fprintf(stdout, "OP_POSTDEC\n"); return;
|
case OP_PREDEC:
|
||||||
|
fprintf(stdout, "OP_PREDEC\n");
|
||||||
|
return;
|
||||||
|
case OP_POSTINC:
|
||||||
|
fprintf(stdout, "OP_POSTINC\n");
|
||||||
|
return;
|
||||||
|
case OP_POSTDEC:
|
||||||
|
fprintf(stdout, "OP_POSTDEC\n");
|
||||||
|
return;
|
||||||
|
|
||||||
case OP_BITNOT: fprintf(stdout, "OP_BITNOT\n"); return;
|
case OP_BITNOT:
|
||||||
case OP_BOOLNOT: fprintf(stdout, "OP_BOOLNOT\n"); return;
|
fprintf(stdout, "OP_BITNOT\n");
|
||||||
case OP_NEGATE: fprintf(stdout, "OP_NEGATE\n"); return;
|
return;
|
||||||
|
case OP_BOOLNOT:
|
||||||
|
fprintf(stdout, "OP_BOOLNOT\n");
|
||||||
|
return;
|
||||||
|
case OP_NEGATE:
|
||||||
|
fprintf(stdout, "OP_NEGATE\n");
|
||||||
|
return;
|
||||||
|
|
||||||
case OP_BOOLCONV: fprintf(stdout, "OP_BOOLCONV\n"); return;
|
case OP_BOOLCONV:
|
||||||
|
fprintf(stdout, "OP_BOOLCONV\n");
|
||||||
|
return;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
DieDecimal("Unknown Dump Operator", Node->Operation);
|
DieDecimal("Unknown Dump Operator", Node->Operation);
|
||||||
|
|
177
src/Lexer.c
177
src/Lexer.c
|
@ -37,7 +37,7 @@ static void ReturnCharToStream(int Char) {
|
||||||
static int NextChar(void) {
|
static int NextChar(void) {
|
||||||
int Char;
|
int Char;
|
||||||
|
|
||||||
if(Overread) {
|
if (Overread) {
|
||||||
Char = Overread;
|
Char = Overread;
|
||||||
Overread = 0;
|
Overread = 0;
|
||||||
return Char;
|
return Char;
|
||||||
|
@ -45,9 +45,9 @@ static int NextChar(void) {
|
||||||
|
|
||||||
Char = fgetc(SourceFile);
|
Char = fgetc(SourceFile);
|
||||||
|
|
||||||
if(Char == '\n')
|
if (Char == '\n')
|
||||||
Line++;
|
Line++;
|
||||||
|
|
||||||
return Char;
|
return Char;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ static int FindChar() {
|
||||||
|
|
||||||
Char = NextChar();
|
Char = NextChar();
|
||||||
|
|
||||||
while(Char == ' ' || Char == '\t' || Char == '\n' || Char == '\r') {
|
while (Char == ' ' || Char == '\t' || Char == '\n' || Char == '\r') {
|
||||||
Char = NextChar();
|
Char = NextChar();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,7 +77,7 @@ static int FindChar() {
|
||||||
|
|
||||||
static int FindDigitFromPos(char* String, char Char) {
|
static int FindDigitFromPos(char* String, char Char) {
|
||||||
char* Result = strchr(String, Char);
|
char* Result = strchr(String, Char);
|
||||||
return(Result ? Result - String : -1);
|
return (Result ? Result - String : -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -91,7 +91,7 @@ static int FindDigitFromPos(char* String, char Char) {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void VerifyToken(int Type, char* TokenExpected) {
|
void VerifyToken(int Type, char* TokenExpected) {
|
||||||
if(CurrentToken.type == Type)
|
if (CurrentToken.type == Type)
|
||||||
Tokenise();
|
Tokenise();
|
||||||
else {
|
else {
|
||||||
printf("Expected %s on line %d\n", TokenExpected, Line);
|
printf("Expected %s on line %d\n", TokenExpected, Line);
|
||||||
|
@ -108,9 +108,9 @@ static struct Token* RejectedToken = NULL;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void RejectToken(struct Token* Token) {
|
void RejectToken(struct Token* Token) {
|
||||||
if(RejectedToken != NULL)
|
if (RejectedToken != NULL)
|
||||||
Die("Cannot reject two tokens in a row!");
|
Die("Cannot reject two tokens in a row!");
|
||||||
|
|
||||||
RejectedToken = Token;
|
RejectedToken = Token;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,7 +137,7 @@ static int ReadInteger(int Char) {
|
||||||
int CurrentChar = 0;
|
int CurrentChar = 0;
|
||||||
int IntegerValue = 0;
|
int IntegerValue = 0;
|
||||||
|
|
||||||
while((CurrentChar = FindDigitFromPos("0123456789", Char)) >= 0) {
|
while ((CurrentChar = FindDigitFromPos("0123456789", Char)) >= 0) {
|
||||||
IntegerValue = IntegerValue * 10 + CurrentChar;
|
IntegerValue = IntegerValue * 10 + CurrentChar;
|
||||||
Char = NextChar();
|
Char = NextChar();
|
||||||
}
|
}
|
||||||
|
@ -165,10 +165,10 @@ static int ReadInteger(int Char) {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static int ReadIdentifier(int Char, char* Buffer, int Limit) {
|
static int ReadIdentifier(int Char, char* Buffer, int Limit) {
|
||||||
int ind = 0;
|
int ind = 0;
|
||||||
|
|
||||||
// This defines the valid chars in a keyword/variable/function.
|
// This defines the valid chars in a keyword/variable/function.
|
||||||
while(isalpha(Char) || isdigit(Char) || Char == '_') {
|
while (isalpha(Char) || isdigit(Char) || Char == '_') {
|
||||||
if (ind >= Limit - 1) {
|
if (ind >= Limit - 1) {
|
||||||
printf("Identifier too long: %d\n", Line);
|
printf("Identifier too long: %d\n", Line);
|
||||||
exit(1);
|
exit(1);
|
||||||
|
@ -199,18 +199,28 @@ static int ReadIdentifier(int Char, char* Buffer, int Limit) {
|
||||||
static int ReadCharLiteral() {
|
static int ReadCharLiteral() {
|
||||||
int Char;
|
int Char;
|
||||||
Char = NextChar();
|
Char = NextChar();
|
||||||
if(Char == '\\') {
|
if (Char == '\\') {
|
||||||
switch(Char = NextChar()) {
|
switch (Char = NextChar()) {
|
||||||
case 'a': return '\a';
|
case 'a':
|
||||||
case 'b': return '\b';
|
return '\a';
|
||||||
case 'f': return '\f';
|
case 'b':
|
||||||
case 'n': return '\n';
|
return '\b';
|
||||||
case 'r': return '\r';
|
case 'f':
|
||||||
case 't': return '\t';
|
return '\f';
|
||||||
case 'v': return '\v';
|
case 'n':
|
||||||
case '\\': return '\\';
|
return '\n';
|
||||||
case '"': return '"';
|
case 'r':
|
||||||
case '\'': return '\'';
|
return '\r';
|
||||||
|
case 't':
|
||||||
|
return '\t';
|
||||||
|
case 'v':
|
||||||
|
return '\v';
|
||||||
|
case '\\':
|
||||||
|
return '\\';
|
||||||
|
case '"':
|
||||||
|
return '"';
|
||||||
|
case '\'':
|
||||||
|
return '\'';
|
||||||
default:
|
default:
|
||||||
DieChar("Unknown Escape: ", Char);
|
DieChar("Unknown Escape: ", Char);
|
||||||
}
|
}
|
||||||
|
@ -236,11 +246,12 @@ static int ReadCharLiteral() {
|
||||||
static int ReadStringLiteral(char* Buffer) {
|
static int ReadStringLiteral(char* Buffer) {
|
||||||
int Char;
|
int Char;
|
||||||
|
|
||||||
for(int i = 0; i < TEXTLEN - 1; i++) {
|
for (int i = 0; i < TEXTLEN - 1; i++) {
|
||||||
if((Char = ReadCharLiteral()) == '"') {
|
if ((Char = ReadCharLiteral()) == '"') {
|
||||||
Buffer[i] = 0; return i;
|
Buffer[i] = 0;
|
||||||
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
Buffer[i] = Char;
|
Buffer[i] = Char;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -265,80 +276,79 @@ static int ReadStringLiteral(char* Buffer) {
|
||||||
*/
|
*/
|
||||||
static int ReadKeyword(char* Str) {
|
static int ReadKeyword(char* Str) {
|
||||||
// First, scan with reference intact.
|
// First, scan with reference intact.
|
||||||
switch(*Str) {
|
switch (*Str) {
|
||||||
// This lets us case against the first char:
|
// This lets us case against the first char:
|
||||||
case ':':
|
case ':':
|
||||||
if(!strcmp(Str, "::"))
|
if (!strcmp(Str, "::"))
|
||||||
return KW_FUNC;
|
return KW_FUNC;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'c':
|
case 'c':
|
||||||
if(!strcmp(Str, "char"))
|
if (!strcmp(Str, "char"))
|
||||||
return TY_CHAR;
|
return TY_CHAR;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'e':
|
case 'e':
|
||||||
if(!strcmp(Str, "else"))
|
if (!strcmp(Str, "else"))
|
||||||
return KW_ELSE;
|
return KW_ELSE;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'f':
|
case 'f':
|
||||||
if(!strcmp(Str, "for"))
|
if (!strcmp(Str, "for"))
|
||||||
return KW_FOR;
|
return KW_FOR;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'i':
|
case 'i':
|
||||||
// alias char, int and long types
|
// alias char, int and long types
|
||||||
|
|
||||||
if(!strcmp(Str, "i8"))
|
if (!strcmp(Str, "i8"))
|
||||||
return TY_CHAR;
|
return TY_CHAR;
|
||||||
if(!strcmp(Str, "i32"))
|
if (!strcmp(Str, "i32"))
|
||||||
return TY_INT;
|
return TY_INT;
|
||||||
if(!strcmp(Str, "i64"))
|
if (!strcmp(Str, "i64"))
|
||||||
return TY_LONG;
|
return TY_LONG;
|
||||||
|
|
||||||
if(!strcmp(Str, "int"))
|
if (!strcmp(Str, "int"))
|
||||||
return TY_INT;
|
return TY_INT;
|
||||||
|
|
||||||
if(!strcmp(Str, "if"))
|
if (!strcmp(Str, "if"))
|
||||||
return KW_IF;
|
return KW_IF;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'l':
|
case 'l':
|
||||||
if(!strcmp(Str, "long"))
|
if (!strcmp(Str, "long"))
|
||||||
return TY_LONG;
|
return TY_LONG;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'p':
|
case 'p':
|
||||||
if(!strcmp(Str, "print"))
|
if (!strcmp(Str, "print"))
|
||||||
return KW_PRINT;
|
return KW_PRINT;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'r':
|
case 'r':
|
||||||
if(!strcmp(Str, "return"))
|
if (!strcmp(Str, "return"))
|
||||||
return KW_RETURN;
|
return KW_RETURN;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 's':
|
case 's':
|
||||||
if(!strcmp(Str, "struct"))
|
if (!strcmp(Str, "struct"))
|
||||||
return KW_STRUCT;
|
return KW_STRUCT;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'v':
|
case 'v':
|
||||||
if(!strcmp(Str, "void"))
|
if (!strcmp(Str, "void"))
|
||||||
return TY_VOID;
|
return TY_VOID;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'w':
|
case 'w':
|
||||||
if(!strcmp(Str, "while"))
|
if (!strcmp(Str, "while"))
|
||||||
return KW_WHILE;
|
return KW_WHILE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -364,7 +374,7 @@ void Tokenise() {
|
||||||
int Char, TokenType;
|
int Char, TokenType;
|
||||||
struct Token* Token = &CurrentToken;
|
struct Token* Token = &CurrentToken;
|
||||||
|
|
||||||
if(RejectedToken != NULL) {
|
if (RejectedToken != NULL) {
|
||||||
Token = RejectedToken;
|
Token = RejectedToken;
|
||||||
RejectedToken = NULL;
|
RejectedToken = NULL;
|
||||||
return;
|
return;
|
||||||
|
@ -372,7 +382,7 @@ void Tokenise() {
|
||||||
|
|
||||||
Char = FindChar();
|
Char = FindChar();
|
||||||
|
|
||||||
switch(Char) {
|
switch (Char) {
|
||||||
case EOF:
|
case EOF:
|
||||||
Token->type = LI_EOF;
|
Token->type = LI_EOF;
|
||||||
return;
|
return;
|
||||||
|
@ -384,7 +394,7 @@ void Tokenise() {
|
||||||
case '+':
|
case '+':
|
||||||
// + can be either "+" or "++".
|
// + can be either "+" or "++".
|
||||||
Char = NextChar();
|
Char = NextChar();
|
||||||
if(Char == '+') {
|
if (Char == '+') {
|
||||||
Token->type = PPMM_PLUS;
|
Token->type = PPMM_PLUS;
|
||||||
} else {
|
} else {
|
||||||
Token->type = AR_PLUS;
|
Token->type = AR_PLUS;
|
||||||
|
@ -395,9 +405,9 @@ void Tokenise() {
|
||||||
case '-':
|
case '-':
|
||||||
// - can be either "-" or "--" or "->"
|
// - can be either "-" or "--" or "->"
|
||||||
Char = NextChar();
|
Char = NextChar();
|
||||||
if(Char == '-') {
|
if (Char == '-') {
|
||||||
Token->type = PPMM_MINUS;
|
Token->type = PPMM_MINUS;
|
||||||
} else if(Char == '>') {
|
} else if (Char == '>') {
|
||||||
Token->type = LI_ARROW;
|
Token->type = LI_ARROW;
|
||||||
} else {
|
} else {
|
||||||
Token->type = AR_MINUS;
|
Token->type = AR_MINUS;
|
||||||
|
@ -415,28 +425,28 @@ void Tokenise() {
|
||||||
|
|
||||||
case '&':
|
case '&':
|
||||||
Char = NextChar();
|
Char = NextChar();
|
||||||
if(Char == '&') {
|
if (Char == '&') {
|
||||||
Token->type = BOOL_AND;
|
Token->type = BOOL_AND;
|
||||||
} else {
|
} else {
|
||||||
Token->type = BIT_AND;
|
Token->type = BIT_AND;
|
||||||
ReturnCharToStream(Char);
|
ReturnCharToStream(Char);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '|':
|
case '|':
|
||||||
Char = NextChar();
|
Char = NextChar();
|
||||||
if(Char == '|') {
|
if (Char == '|') {
|
||||||
Token->type = BOOL_OR;
|
Token->type = BOOL_OR;
|
||||||
} else {
|
} else {
|
||||||
Token->type = BIT_OR;
|
Token->type = BIT_OR;
|
||||||
ReturnCharToStream(Char);
|
ReturnCharToStream(Char);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '^':
|
case '^':
|
||||||
Token->type = BIT_XOR;
|
Token->type = BIT_XOR;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '~':
|
case '~':
|
||||||
Token->type = BIT_NOT;
|
Token->type = BIT_NOT;
|
||||||
break;
|
break;
|
||||||
|
@ -444,40 +454,40 @@ void Tokenise() {
|
||||||
case ',':
|
case ',':
|
||||||
Token->type = LI_COM;
|
Token->type = LI_COM;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '=':
|
case '=':
|
||||||
Char = NextChar();
|
Char = NextChar();
|
||||||
// If the next char is =, we have ==, the compare equality token.
|
// If the next char is =, we have ==, the compare equality token.
|
||||||
if(Char == '?') {
|
if (Char == '?') {
|
||||||
Token->type = CMP_EQUAL;
|
Token->type = CMP_EQUAL;
|
||||||
// if the next char is >, we have =>, the greater than or equal token.
|
// if the next char is >, we have =>, the greater than or equal token.
|
||||||
} else if(Char == '>') {
|
} else if (Char == '>') {
|
||||||
Token->type = CMP_GTE;
|
Token->type = CMP_GTE;
|
||||||
// If none of the above match, we have = and an extra char. Return the char and set the token
|
// If none of the above match, we have = and an extra char. Return the char and set the token
|
||||||
} else {
|
} else {
|
||||||
ReturnCharToStream(Char);
|
ReturnCharToStream(Char);
|
||||||
Token->type = LI_EQUAL;
|
Token->type = LI_EQUAL;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '!':
|
case '!':
|
||||||
Char = NextChar();
|
Char = NextChar();
|
||||||
// If the next char is =, we have !=, the compare inequality operator.
|
// If the next char is =, we have !=, the compare inequality operator.
|
||||||
if(Char == '=') {
|
if (Char == '=') {
|
||||||
Token->type = CMP_INEQ;
|
Token->type = CMP_INEQ;
|
||||||
// Otherwise, we have a spare char
|
// Otherwise, we have a spare char
|
||||||
} else {
|
} else {
|
||||||
Token->type = BOOL_INVERT;
|
Token->type = BOOL_INVERT;
|
||||||
ReturnCharToStream(Char);
|
ReturnCharToStream(Char);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '<':
|
case '<':
|
||||||
Char = NextChar();
|
Char = NextChar();
|
||||||
// If the next char is =, we have <=, the less than or equal comparator.
|
// If the next char is =, we have <=, the less than or equal comparator.
|
||||||
if(Char == '=') {
|
if (Char == '=') {
|
||||||
Token->type = CMP_LTE;
|
Token->type = CMP_LTE;
|
||||||
} else if(Char == '<') { // But if the next char is <, we have << - the Shift Left operator.
|
} else if (Char == '<') { // But if the next char is <, we have << - the Shift Left operator.
|
||||||
Token->type = SH_LEFT;
|
Token->type = SH_LEFT;
|
||||||
} else {
|
} else {
|
||||||
ReturnCharToStream(Char);
|
ReturnCharToStream(Char);
|
||||||
|
@ -488,7 +498,7 @@ void Tokenise() {
|
||||||
case '>':
|
case '>':
|
||||||
// For >, Less than or equal is => so we can ignore it, but the Shift Right operator is >>.
|
// For >, Less than or equal is => so we can ignore it, but the Shift Right operator is >>.
|
||||||
Char = NextChar();
|
Char = NextChar();
|
||||||
if(Char == '>') {
|
if (Char == '>') {
|
||||||
Token->type = SH_RIGHT;
|
Token->type = SH_RIGHT;
|
||||||
} else {
|
} else {
|
||||||
Token->type = CMP_GT;
|
Token->type = CMP_GT;
|
||||||
|
@ -503,11 +513,11 @@ void Tokenise() {
|
||||||
case '(':
|
case '(':
|
||||||
Token->type = LI_LPARE;
|
Token->type = LI_LPARE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ')':
|
case ')':
|
||||||
Token->type = LI_RPARE;
|
Token->type = LI_RPARE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '{':
|
case '{':
|
||||||
Token->type = LI_LBRAC;
|
Token->type = LI_LBRAC;
|
||||||
break;
|
break;
|
||||||
|
@ -519,15 +529,15 @@ void Tokenise() {
|
||||||
case '[':
|
case '[':
|
||||||
Token->type = LI_LBRAS;
|
Token->type = LI_LBRAS;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ']':
|
case ']':
|
||||||
Token->type = LI_RBRAS;
|
Token->type = LI_RBRAS;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ':':
|
case ':':
|
||||||
Char = NextChar();
|
Char = NextChar();
|
||||||
|
|
||||||
if(Char == ':') {
|
if (Char == ':') {
|
||||||
Token->type = KW_FUNC;
|
Token->type = KW_FUNC;
|
||||||
} else {
|
} else {
|
||||||
ReturnCharToStream(Char);
|
ReturnCharToStream(Char);
|
||||||
|
@ -538,7 +548,7 @@ void Tokenise() {
|
||||||
Token->value = ReadCharLiteral();
|
Token->value = ReadCharLiteral();
|
||||||
Token->type = LI_INT;
|
Token->type = LI_INT;
|
||||||
|
|
||||||
if(NextChar() != '\'')
|
if (NextChar() != '\'')
|
||||||
Die("Expected '\\'' at the end of a character.");
|
Die("Expected '\\'' at the end of a character.");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -548,27 +558,28 @@ void Tokenise() {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if(isdigit(Char)) {
|
if (isdigit(Char)) {
|
||||||
|
|
||||||
Token->value = ReadInteger(Char);
|
Token->value = ReadInteger(Char);
|
||||||
Token->type = LI_INT;
|
Token->type = LI_INT;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
} else if(isalpha(Char) || Char == '_') { // This is what defines what a variable/function/keyword can START with.
|
} else if (isalpha(Char) ||
|
||||||
|
Char == '_') { // This is what defines what a variable/function/keyword can START with.
|
||||||
ReadIdentifier(Char, CurrentIdentifier, TEXTLEN);
|
ReadIdentifier(Char, CurrentIdentifier, TEXTLEN);
|
||||||
|
|
||||||
if(TokenType = ReadKeyword(CurrentIdentifier)) {
|
if (TokenType = ReadKeyword(CurrentIdentifier)) {
|
||||||
Token->type = TokenType;
|
Token->type = TokenType;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Token->type = TY_IDENTIFIER;
|
Token->type = TY_IDENTIFIER;
|
||||||
break;
|
break;
|
||||||
//printf("Line %d: Unrecognized symbol %s\n", CurrentIdentifier, Line);
|
//printf.er("Line %d: Unrecognized symbol %s\n", CurrentIdentifier, Line);
|
||||||
//exit(1);
|
//exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DieChar("Unrecognized character", Char);
|
DieChar("Unrecognized character", Char);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
161
src/Main.c
161
src/Main.c
|
@ -4,96 +4,99 @@
|
||||||
/*************/
|
/*************/
|
||||||
|
|
||||||
#include <Defs.h>
|
#include <Defs.h>
|
||||||
|
|
||||||
#define extern_
|
#define extern_
|
||||||
|
|
||||||
#include <Data.h>
|
#include <Data.h>
|
||||||
|
|
||||||
#undef extern_
|
#undef extern_
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
|
|
||||||
int TypeSizes[5] = { 0, 1, 4, 8, 0}; // in BYTES
|
|
||||||
|
|
||||||
char* TokenNames[] = {
|
int TypeSizes[5] = {0, 1, 4, 8, 0}; // in BYTES
|
||||||
"End of file",
|
|
||||||
"Equivalency",
|
|
||||||
|
|
||||||
"Boolean Logic OR",
|
char* TokenNames[] = {
|
||||||
"Boolean Logic AND",
|
"End of file",
|
||||||
|
"Equivalency",
|
||||||
|
|
||||||
"Bitwise OR",
|
"Boolean Logic OR",
|
||||||
"Bitwise XOR",
|
"Boolean Logic AND",
|
||||||
"Bitwise AND",
|
|
||||||
|
|
||||||
"Equality Check",
|
"Bitwise OR",
|
||||||
"Inequality Check",
|
"Bitwise XOR",
|
||||||
"Less Than",
|
"Bitwise AND",
|
||||||
"Greater Than",
|
|
||||||
"Less Than or Equal",
|
|
||||||
"Greater Than or Equal",
|
|
||||||
|
|
||||||
"Left Shift",
|
"Equality Check",
|
||||||
"Right Shift",
|
"Inequality Check",
|
||||||
|
"Less Than",
|
||||||
|
"Greater Than",
|
||||||
|
"Less Than or Equal",
|
||||||
|
"Greater Than or Equal",
|
||||||
|
|
||||||
"Addition",
|
"Left Shift",
|
||||||
"Subtraction",
|
"Right Shift",
|
||||||
"Multiplication",
|
|
||||||
"Division",
|
|
||||||
|
|
||||||
"Increment",
|
"Addition",
|
||||||
"Decrement",
|
"Subtraction",
|
||||||
|
"Multiplication",
|
||||||
|
"Division",
|
||||||
|
|
||||||
"Statement Logical Invert",
|
"Increment",
|
||||||
"Bitwise Invert",
|
"Decrement",
|
||||||
|
|
||||||
"Integer literal",
|
|
||||||
"String literal",
|
|
||||||
"Statement End",
|
|
||||||
|
|
||||||
"Compound Block Start",
|
"Statement Logical Invert",
|
||||||
"Compound Block End",
|
"Bitwise Invert",
|
||||||
|
|
||||||
"Array index start",
|
"Integer literal",
|
||||||
"Array index end",
|
"String literal",
|
||||||
|
"Statement End",
|
||||||
|
|
||||||
"Logical Block Start",
|
"Compound Block Start",
|
||||||
"Logical Block End",
|
"Compound Block End",
|
||||||
|
|
||||||
"Comma",
|
"Array index start",
|
||||||
"Dot",
|
"Array index end",
|
||||||
"Arrow",
|
|
||||||
|
|
||||||
"Identifier",
|
"Logical Block Start",
|
||||||
"None Type",
|
"Logical Block End",
|
||||||
"Char Type",
|
|
||||||
"Int Type",
|
|
||||||
"Long Type",
|
|
||||||
"Void Type",
|
|
||||||
|
|
||||||
"Function keyword",
|
"Comma",
|
||||||
"Print Keyword",
|
"Dot",
|
||||||
"If keyword",
|
"Arrow",
|
||||||
"Else keyword",
|
|
||||||
"While keyword",
|
|
||||||
"For keyword",
|
|
||||||
|
|
||||||
"Return keyword",
|
"Identifier",
|
||||||
|
"None Type",
|
||||||
"Struct keyword"
|
"Char Type",
|
||||||
|
"Int Type",
|
||||||
|
"Long Type",
|
||||||
|
"Void Type",
|
||||||
|
|
||||||
|
"Function keyword",
|
||||||
|
"Print Keyword",
|
||||||
|
"If keyword",
|
||||||
|
"Else keyword",
|
||||||
|
"While keyword",
|
||||||
|
"For keyword",
|
||||||
|
|
||||||
|
"Return keyword",
|
||||||
|
|
||||||
|
"Struct keyword"
|
||||||
};
|
};
|
||||||
|
|
||||||
char* ScopeNames[] = {
|
char* ScopeNames[] = {
|
||||||
"INVALID",
|
"INVALID",
|
||||||
"GLOBAL",
|
"GLOBAL",
|
||||||
"STRUCT",
|
"STRUCT",
|
||||||
"ENUM",
|
"ENUM",
|
||||||
"MEMBER",
|
"MEMBER",
|
||||||
"PARAMETER",
|
"PARAMETER",
|
||||||
"LOCAL"
|
"LOCAL"
|
||||||
};
|
};
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
// Option initialisers
|
// Option initialisers
|
||||||
OptDumpTree = false;
|
OptDumpTree = false;
|
||||||
OptKeepAssembly = false;
|
OptKeepAssembly = true;
|
||||||
OptAssembleFiles = false;
|
OptAssembleFiles = false;
|
||||||
OptLinkFiles = true;
|
OptLinkFiles = true;
|
||||||
OptVerboseOutput = false;
|
OptVerboseOutput = false;
|
||||||
|
@ -104,24 +107,24 @@ int main(int argc, char* argv[]) {
|
||||||
|
|
||||||
// Parse command line arguments.
|
// Parse command line arguments.
|
||||||
int i;
|
int i;
|
||||||
for(i = 1/*skip 0*/; i < argc; i++) {
|
for (i = 1/*skip 0*/; i < argc; i++) {
|
||||||
// If we're not a flag, we can skip.
|
// If we're not a flag, we can skip.
|
||||||
// We only care about flags in rows.
|
// We only care about flags in rows.
|
||||||
// ie. erc >> -v -T -o << test.exe src/main.er
|
// ie. erc >> -v -T -o << test.exe src/main.er
|
||||||
if(*argv[i] != '-')
|
if (*argv[i] != '-')
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Once we identify a flag, we need to make sure it's not just a minus in-place.
|
// Once we identify a flag, we need to make sure it's not just a minus in-place.
|
||||||
for(int j = 1; (*argv[i] == '-') && argv[i][j]; j++) {
|
for (int j = 1; (*argv[i] == '-') && argv[i][j]; j++) {
|
||||||
// Finally, identify what option is being invoked.
|
// Finally, identify what option is being invoked.
|
||||||
switch(argv[i][j]) {
|
switch (argv[i][j]) {
|
||||||
case 'o': // output
|
case 'o': // output
|
||||||
OutputFileName = argv[++i];
|
OutputFileName = argv[++i];
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 'T': // print Tree (debug)
|
||||||
|
OptDumpTree = true;
|
||||||
break;
|
break;
|
||||||
case 'T': // Debug
|
|
||||||
OptDumpTree = true;
|
|
||||||
break;
|
|
||||||
case 'c': // Compile only
|
case 'c': // Compile only
|
||||||
OptAssembleFiles = true;
|
OptAssembleFiles = true;
|
||||||
OptKeepAssembly = false;
|
OptKeepAssembly = false;
|
||||||
|
@ -142,19 +145,19 @@ int main(int argc, char* argv[]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we didn't provide anything other than flags, we need to show how to use the program.
|
// If we didn't provide anything other than flags, we need to show how to use the program.
|
||||||
if(i >= argc)
|
if (i >= argc)
|
||||||
DisplayUsage(argv[0]);
|
DisplayUsage(argv[0]);
|
||||||
|
|
||||||
// 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) {
|
||||||
// Compile the file by invoking the Delegate
|
// Compile the file by invoking the Delegate
|
||||||
CurrentASMFile = Compile(argv[i]);
|
CurrentASMFile = Compile(argv[i]);
|
||||||
if(OptLinkFiles || OptAssembleFiles) {
|
if (OptLinkFiles || OptAssembleFiles) {
|
||||||
// If we need to assemble (or link, which requires assembly)
|
// If we need to assemble (or link, which requires assembly)
|
||||||
// then we invoke the Delegate again
|
// then we invoke the Delegate again
|
||||||
CurrentObjectFile = Assemble(CurrentASMFile);
|
CurrentObjectFile = Assemble(CurrentASMFile);
|
||||||
// We can only keep track of 99 objects, so we should crash at 98 to ensure we have enough room for the output file too.
|
// We can only keep track of 99 objects, so we should crash at 98 to ensure we have enough room for the output file too.
|
||||||
if(ObjectCount == 98) {
|
if (ObjectCount == 98) {
|
||||||
fprintf(stderr, "Too many inputs");
|
fprintf(stderr, "Too many inputs");
|
||||||
return 1; // We use return because we're in main, rather than invoking Die.
|
return 1; // We use return because we're in main, rather than invoking Die.
|
||||||
}
|
}
|
||||||
|
@ -165,19 +168,19 @@ int main(int argc, char* argv[]) {
|
||||||
ObjectFiles[ObjectCount] = NULL;
|
ObjectFiles[ObjectCount] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!OptKeepAssembly)
|
if (!OptKeepAssembly)
|
||||||
// unlink = delete
|
// unlink = delete
|
||||||
unlink(CurrentASMFile);
|
unlink(CurrentASMFile);
|
||||||
|
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(OptLinkFiles) {
|
if (OptLinkFiles) {
|
||||||
// If needed, invoke the Delegate one last time.
|
// If needed, invoke the Delegate one last time.
|
||||||
Link(OutputFileName, ObjectFiles);
|
Link(OutputFileName, ObjectFiles);
|
||||||
if(!OptAssembleFiles) {
|
if (!OptAssembleFiles) {
|
||||||
// Even though we need to assemble to link, we can respect the user's options and delete the intermediary files.
|
// Even though we need to assemble to link, we can respect the user's options and delete the intermediary files.
|
||||||
for(i = 0; ObjectFiles[i] != NULL; i++)
|
for (i = 0; ObjectFiles[i] != NULL; i++)
|
||||||
unlink(ObjectFiles[i]);
|
unlink(ObjectFiles[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
157
src/Parser.c
157
src/Parser.c
|
@ -16,17 +16,17 @@
|
||||||
* This allows for things like the common Order of Operations.
|
* This allows for things like the common Order of Operations.
|
||||||
*/
|
*/
|
||||||
static int Precedence[] = {
|
static int Precedence[] = {
|
||||||
0, 10, // EOF, ASSIGN
|
0, 10, // EOF, ASSIGN
|
||||||
20, 30, // || &&
|
20, 30, // || &&
|
||||||
40, 50, // | ^
|
40, 50, // | ^
|
||||||
60, 70, // & =?
|
60, 70, // & =?
|
||||||
70, 80, // != <
|
70, 80, // != <
|
||||||
80, 80, // > <=
|
80, 80, // > <=
|
||||||
80, 90, // => <<
|
80, 90, // => <<
|
||||||
90, 100, // >> +
|
90, 100, // >> +
|
||||||
100, 110, // - *
|
100, 110, // - *
|
||||||
110 // /
|
110 // /
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Handles gathering the precedence of an operator from its token,
|
* Handles gathering the precedence of an operator from its token,
|
||||||
|
@ -38,8 +38,8 @@ static int Precedence[] = {
|
||||||
static int OperatorPrecedence(int Token) {
|
static int OperatorPrecedence(int Token) {
|
||||||
int Prec = Precedence[Token];
|
int Prec = Precedence[Token];
|
||||||
|
|
||||||
if(Prec == 0 || Token >= PPMM_PLUS) {
|
if (Prec == 0 || Token >= PPMM_PLUS) {
|
||||||
if(Token == TY_IDENTIFIER)
|
if (Token == TY_IDENTIFIER)
|
||||||
DieMessage("Attempting to determine operator precedence of identifier", CurrentIdentifier);
|
DieMessage("Attempting to determine operator precedence of identifier", CurrentIdentifier);
|
||||||
|
|
||||||
DieMessage("Attempting to determine operator precedence of an EOF or INT literal", TokenNames[Token]);
|
DieMessage("Attempting to determine operator precedence of an EOF or INT literal", TokenNames[Token]);
|
||||||
|
@ -56,7 +56,7 @@ static int OperatorPrecedence(int Token) {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int IsRightExpr(int Token) {
|
static int IsRightExpr(int Token) {
|
||||||
return (Token == LI_EQUAL);
|
return (Token == LI_EQUAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* * * * * * * * * * * * * * * * * * * * * * * *
|
/* * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
@ -92,12 +92,12 @@ struct ASTNode* ConstructASTNode(int Operation, int Type,
|
||||||
struct ASTNode* Right,
|
struct ASTNode* Right,
|
||||||
struct SymbolTableEntry* Symbol,
|
struct SymbolTableEntry* Symbol,
|
||||||
int IntValue) {
|
int IntValue) {
|
||||||
|
|
||||||
struct ASTNode* Node;
|
struct ASTNode* Node;
|
||||||
|
|
||||||
Node = (struct ASTNode*) malloc(sizeof(struct ASTNode));
|
Node = (struct ASTNode*) malloc(sizeof(struct ASTNode));
|
||||||
|
|
||||||
if(!Node)
|
if (!Node)
|
||||||
Die("Unable to allocate node!");
|
Die("Unable to allocate node!");
|
||||||
|
|
||||||
|
|
||||||
|
@ -135,7 +135,8 @@ struct ASTNode* ConstructASTLeaf(int Operation, int Type, struct SymbolTableEntr
|
||||||
* @param IntValue: The integer value encoded by this Node, if applicable.
|
* @param IntValue: The integer value encoded by this Node, if applicable.
|
||||||
* @return a newly constructed AST Node
|
* @return a newly constructed AST Node
|
||||||
*/
|
*/
|
||||||
struct ASTNode* ConstructASTBranch(int Operation, int Type, struct ASTNode* Left, struct SymbolTableEntry* Symbol, int 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);
|
return ConstructASTNode(Operation, Type, Left, NULL, NULL, Symbol, IntValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,7 +153,7 @@ struct ASTNode* ConstructASTBranch(int Operation, int Type, struct ASTNode* Left
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int ParseTokenToOperation(int Token) {
|
int ParseTokenToOperation(int Token) {
|
||||||
if(Token > LI_EOF && Token < LI_INT)
|
if (Token > LI_EOF && Token < LI_INT)
|
||||||
return Token;
|
return Token;
|
||||||
|
|
||||||
DieDecimal("ParseToken: Unknown token", Token);
|
DieDecimal("ParseToken: Unknown token", Token);
|
||||||
|
@ -172,12 +173,12 @@ struct ASTNode* ParsePrimary(void) {
|
||||||
struct ASTNode* Node;
|
struct ASTNode* Node;
|
||||||
int ID;
|
int ID;
|
||||||
|
|
||||||
switch(CurrentToken.type) {
|
switch (CurrentToken.type) {
|
||||||
case LI_INT:
|
case LI_INT:
|
||||||
|
|
||||||
if((CurrentToken.value >= 0) && (CurrentToken.value < 256))
|
if ((CurrentToken.value >= 0) && (CurrentToken.value < 256))
|
||||||
Node = ConstructASTLeaf(TERM_INTLITERAL, RET_CHAR, NULL, CurrentToken.value);
|
Node = ConstructASTLeaf(TERM_INTLITERAL, RET_CHAR, NULL, CurrentToken.value);
|
||||||
else
|
else
|
||||||
Node = ConstructASTLeaf(TERM_INTLITERAL, RET_INT, NULL, CurrentToken.value);
|
Node = ConstructASTLeaf(TERM_INTLITERAL, RET_INT, NULL, CurrentToken.value);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -201,7 +202,7 @@ struct ASTNode* ParsePrimary(void) {
|
||||||
return Node;
|
return Node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Tokenise();
|
Tokenise();
|
||||||
|
|
||||||
return Node;
|
return Node;
|
||||||
|
@ -223,8 +224,8 @@ struct ASTNode* ParsePrimary(void) {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
struct ASTNode* ParsePrecedenceASTNode(int PreviousTokenPrecedence) {
|
struct ASTNode* ParsePrecedenceASTNode(int PreviousTokenPrecedence) {
|
||||||
struct ASTNode* LeftNode, *RightNode;
|
struct ASTNode* LeftNode, * RightNode;
|
||||||
struct ASTNode* LeftTemp, *RightTemp;
|
struct ASTNode* LeftTemp, * RightTemp;
|
||||||
// int LeftType, RightType;
|
// int LeftType, RightType;
|
||||||
int NodeType, OpType;
|
int NodeType, OpType;
|
||||||
|
|
||||||
|
@ -232,13 +233,15 @@ struct ASTNode* ParsePrecedenceASTNode(int PreviousTokenPrecedence) {
|
||||||
|
|
||||||
NodeType = CurrentToken.type;
|
NodeType = CurrentToken.type;
|
||||||
|
|
||||||
if(NodeType == LI_SEMIC || NodeType == LI_RPARE || NodeType == LI_RBRAS || NodeType == LI_COM) {
|
if (NodeType == LI_SEMIC || NodeType == LI_RPARE || NodeType == LI_RBRAS || NodeType == LI_COM) {
|
||||||
LeftNode->RVal = 1; return LeftNode;
|
LeftNode->RVal = 1;
|
||||||
|
return LeftNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
while((OperatorPrecedence(NodeType) > PreviousTokenPrecedence) || (IsRightExpr(OpType) && OperatorPrecedence(OpType) == PreviousTokenPrecedence)) {
|
while ((OperatorPrecedence(NodeType) > PreviousTokenPrecedence) ||
|
||||||
|
(IsRightExpr(OpType) && OperatorPrecedence(OpType) == PreviousTokenPrecedence)) {
|
||||||
Tokenise();
|
Tokenise();
|
||||||
if(CurrentToken.type == LI_RPARE)
|
if (CurrentToken.type == LI_RPARE)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
RightNode = ParsePrecedenceASTNode(Precedence[NodeType]);
|
RightNode = ParsePrecedenceASTNode(Precedence[NodeType]);
|
||||||
|
@ -251,13 +254,13 @@ struct ASTNode* ParsePrecedenceASTNode(int PreviousTokenPrecedence) {
|
||||||
|
|
||||||
OpType = ParseTokenToOperation(NodeType);
|
OpType = ParseTokenToOperation(NodeType);
|
||||||
|
|
||||||
if(OpType == OP_ASSIGN) {
|
if (OpType == OP_ASSIGN) {
|
||||||
printf("\tParsePrecedenceASTNode: Assignment statement\r\n");
|
printf("\tParsePrecedenceASTNode: Assignment statement\r\n");
|
||||||
RightNode->RVal = 1;
|
RightNode->RVal = 1;
|
||||||
LeftNode->RVal = 0;
|
LeftNode->RVal = 0;
|
||||||
|
|
||||||
RightNode = MutateType(RightNode, LeftNode->ExprType, 0);
|
RightNode = MutateType(RightNode, LeftNode->ExprType, 0);
|
||||||
if(LeftNode == NULL)
|
if (RightNode == NULL)
|
||||||
Die("Incompatible Expression encountered in assignment");
|
Die("Incompatible Expression encountered in assignment");
|
||||||
|
|
||||||
// LeftNode holds the target, the target variable in this case
|
// LeftNode holds the target, the target variable in this case
|
||||||
|
@ -266,7 +269,7 @@ struct ASTNode* ParsePrecedenceASTNode(int PreviousTokenPrecedence) {
|
||||||
LeftTemp = LeftNode;
|
LeftTemp = LeftNode;
|
||||||
LeftNode = RightNode;
|
LeftNode = RightNode;
|
||||||
RightNode = LeftTemp;
|
RightNode = LeftTemp;
|
||||||
|
|
||||||
// Clear temps as ensurance
|
// Clear temps as ensurance
|
||||||
RightTemp = NULL;
|
RightTemp = NULL;
|
||||||
LeftTemp = NULL;
|
LeftTemp = NULL;
|
||||||
|
@ -282,19 +285,20 @@ struct ASTNode* ParsePrecedenceASTNode(int PreviousTokenPrecedence) {
|
||||||
* If both are null, the types are incompatible.
|
* If both are null, the types are incompatible.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if(LeftTemp == NULL && RightTemp == NULL)
|
if (LeftTemp == NULL && RightTemp == NULL)
|
||||||
Die("Incompatible types in parsing nodes");
|
Die("Incompatible types in parsing nodes");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the left was valid, or valid for
|
* If the left was valid, or valid for
|
||||||
* expansion, then it will be non-null.
|
* expansion, then it will be non-null.
|
||||||
*
|
*
|
||||||
* If it was valid, then this will be
|
* If it was valid, then this will be
|
||||||
* equivalent to LeftNode = LeftNode
|
* equivalent to LeftNode = LeftNode
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if(LeftTemp)
|
|
||||||
LeftNode = LeftTemp;
|
if (LeftTemp != NULL)
|
||||||
|
LeftNode = LeftTemp; //ConstructASTBranch(LeftType, RightNode->ExprType, LeftNode, 0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Same here, but there is a higher chance
|
* Same here, but there is a higher chance
|
||||||
|
@ -302,26 +306,19 @@ struct ASTNode* ParsePrecedenceASTNode(int PreviousTokenPrecedence) {
|
||||||
* to the nature of widening types.
|
* to the nature of widening types.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if(RightTemp)
|
if (RightTemp != NULL)
|
||||||
RightNode = RightTemp;
|
RightNode = RightTemp; // ConstructASTBranch(RightType, LeftNode->ExprType, RightNode, 0);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
LeftNode = ConstructASTNode(ParseTokenToOperation(NodeType), LeftNode->ExprType, LeftNode, NULL, RightNode,
|
||||||
* Checks over, back to normal parsing.
|
NULL, 0);
|
||||||
*/
|
|
||||||
|
|
||||||
if(LeftTemp != NULL)
|
|
||||||
LeftNode = LeftTemp; //ConstructASTBranch(LeftType, RightNode->ExprType, LeftNode, 0);
|
|
||||||
if(RightTemp != NULL)
|
|
||||||
RightNode = RightTemp; // ConstructASTBranch(RightType, LeftNode->ExprType, RightNode, 0);
|
|
||||||
|
|
||||||
LeftNode = ConstructASTNode(ParseTokenToOperation(NodeType), LeftNode->ExprType, LeftNode, NULL, RightNode, NULL, 0);
|
|
||||||
NodeType = CurrentToken.type;
|
NodeType = CurrentToken.type;
|
||||||
if(NodeType == LI_SEMIC || NodeType == LI_RPARE || NodeType == LI_RBRAS) {
|
if (NodeType == LI_SEMIC || NodeType == LI_RPARE || NodeType == LI_RBRAS) {
|
||||||
LeftNode->RVal = 1;
|
LeftNode->RVal = 1;
|
||||||
return LeftNode;
|
return LeftNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
LeftNode->RVal = 1;
|
LeftNode->RVal = 1;
|
||||||
return LeftNode;
|
return LeftNode;
|
||||||
|
@ -348,7 +345,7 @@ struct ASTNode* CallFunction() {
|
||||||
struct SymbolTableEntry* Function;
|
struct SymbolTableEntry* Function;
|
||||||
|
|
||||||
//TODO: Test structural type!
|
//TODO: Test structural type!
|
||||||
if((Function = FindSymbol(CurrentIdentifier)) == NULL || (Function->Structure != ST_FUNC))
|
if ((Function = FindSymbol(CurrentIdentifier)) == NULL || (Function->Structure != ST_FUNC))
|
||||||
DieMessage("Undeclared function", CurrentIdentifier);
|
DieMessage("Undeclared function", CurrentIdentifier);
|
||||||
|
|
||||||
VerifyToken(LI_LPARE, "(");
|
VerifyToken(LI_LPARE, "(");
|
||||||
|
@ -378,16 +375,16 @@ struct ASTNode* CallFunction() {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
struct ASTNode* GetExpressionList() {
|
struct ASTNode* GetExpressionList() {
|
||||||
struct ASTNode* Tree = NULL, *Child = NULL;
|
struct ASTNode* Tree = NULL, * Child = NULL;
|
||||||
int Count;
|
int Count;
|
||||||
|
|
||||||
while(CurrentToken.type != LI_RPARE) {
|
while (CurrentToken.type != LI_RPARE) {
|
||||||
Child = ParsePrecedenceASTNode(0);
|
Child = ParsePrecedenceASTNode(0);
|
||||||
Count++;
|
Count++;
|
||||||
|
|
||||||
Tree = ConstructASTNode(OP_COMP, PointerTo(RET_VOID), Tree, NULL, Child, NULL, Count);
|
Tree = ConstructASTNode(OP_COMP, PointerTo(RET_VOID), Tree, NULL, Child, NULL, Count);
|
||||||
|
|
||||||
switch(CurrentToken.type) {
|
switch (CurrentToken.type) {
|
||||||
case LI_COM:
|
case LI_COM:
|
||||||
Tokenise();
|
Tokenise();
|
||||||
break;
|
break;
|
||||||
|
@ -420,9 +417,9 @@ struct ASTNode* GetExpressionList() {
|
||||||
*/
|
*/
|
||||||
struct ASTNode* ParseStatement(void) {
|
struct ASTNode* ParseStatement(void) {
|
||||||
int Type;
|
int Type;
|
||||||
|
|
||||||
printf("\t\tBranch leads to here, type %s/%d\r\n", TokenNames[CurrentToken.type], CurrentToken.type);
|
printf("\t\tBranch leads to here, type %s/%d\r\n", TokenNames[CurrentToken.type], CurrentToken.type);
|
||||||
switch(CurrentToken.type) {
|
switch (CurrentToken.type) {
|
||||||
case TY_CHAR:
|
case TY_CHAR:
|
||||||
case TY_LONG:
|
case TY_LONG:
|
||||||
case TY_INT:
|
case TY_INT:
|
||||||
|
@ -435,16 +432,16 @@ struct ASTNode* ParseStatement(void) {
|
||||||
|
|
||||||
case KW_IF:
|
case KW_IF:
|
||||||
return IfStatement();
|
return IfStatement();
|
||||||
|
|
||||||
case KW_WHILE:
|
case KW_WHILE:
|
||||||
return WhileStatement();
|
return WhileStatement();
|
||||||
|
|
||||||
case KW_FOR:
|
case KW_FOR:
|
||||||
return ForStatement();
|
return ForStatement();
|
||||||
|
|
||||||
case KW_RETURN:
|
case KW_RETURN:
|
||||||
return ReturnStatement();
|
return ReturnStatement();
|
||||||
|
|
||||||
default:
|
default:
|
||||||
ParsePrecedenceASTNode(0);
|
ParsePrecedenceASTNode(0);
|
||||||
}
|
}
|
||||||
|
@ -468,29 +465,29 @@ struct ASTNode* ParseStatement(void) {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
struct ASTNode* ParseCompound() {
|
struct ASTNode* ParseCompound() {
|
||||||
struct ASTNode* Left = NULL, *Tree;
|
struct ASTNode* Left = NULL, * Tree;
|
||||||
|
|
||||||
// Compound statements are defined by comprising
|
// Compound statements are defined by comprising
|
||||||
// multiple statements inside { a bracket block }
|
// multiple statements inside { a bracket block }
|
||||||
VerifyToken(LI_LBRAC, "{");
|
VerifyToken(LI_LBRAC, "{");
|
||||||
|
|
||||||
while(1) {
|
while (1) {
|
||||||
printf("\tNew branch in compound\n");
|
printf("\tNew branch in compound\n");
|
||||||
|
|
||||||
Tree = ParseStatement();
|
Tree = ParseStatement();
|
||||||
|
|
||||||
if(Tree && (Tree->Operation == OP_PRINT || Tree->Operation == OP_ASSIGN
|
if (Tree && (Tree->Operation == OP_PRINT || Tree->Operation == OP_ASSIGN
|
||||||
|| Tree->Operation == OP_RET || Tree->Operation == OP_CALL))
|
|| Tree->Operation == OP_RET || Tree->Operation == OP_CALL))
|
||||||
VerifyToken(LI_SEMIC, ";");
|
VerifyToken(LI_SEMIC, ";");
|
||||||
|
|
||||||
if(Tree) {
|
if (Tree) {
|
||||||
if(Left == NULL)
|
if (Left == NULL)
|
||||||
Left = Tree;
|
Left = Tree;
|
||||||
else
|
else
|
||||||
Left = ConstructASTNode(OP_COMP, RET_NONE, Left, NULL, Tree, NULL, 0);
|
Left = ConstructASTNode(OP_COMP, RET_NONE, Left, NULL, Tree, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(CurrentToken.type == LI_RBRAC) {
|
if (CurrentToken.type == LI_RBRAC) {
|
||||||
VerifyToken(LI_RBRAC, "}");
|
VerifyToken(LI_RBRAC, "}");
|
||||||
return Left;
|
return Left;
|
||||||
}
|
}
|
||||||
|
@ -519,35 +516,35 @@ void ParseGlobals() {
|
||||||
|
|
||||||
printf("Parsing global definitions\r\n");
|
printf("Parsing global definitions\r\n");
|
||||||
|
|
||||||
while(1) {
|
while (1) {
|
||||||
|
|
||||||
// We loop early if there's a struct, and since a struct may be the last
|
// We loop early if there's a struct, and since a struct may be the last
|
||||||
// thing in a file, we need to check for eof before anything else
|
// thing in a file, we need to check for eof before anything else
|
||||||
if(CurrentToken.type == LI_EOF)
|
if (CurrentToken.type == LI_EOF)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
printf("New definition incoming..\r\n\n");
|
printf("New definition incoming..\r\n\n");
|
||||||
Type = ParseOptionalPointer(&Composite);
|
Type = ParseOptionalPointer(&Composite);
|
||||||
|
|
||||||
//TODO: converge pathways on this block?
|
//TODO: converge pathways on this block?
|
||||||
if(CurrentToken.type == KW_FUNC) {
|
if (CurrentToken.type == KW_FUNC) {
|
||||||
VerifyToken(KW_FUNC, "::");
|
VerifyToken(KW_FUNC, "::");
|
||||||
FunctionComing = 1;
|
FunctionComing = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Structs are parsed fully in ParseOptionalPointer
|
// Structs are parsed fully in ParseOptionalPointer
|
||||||
// TODO: FIX THAT!!
|
// TODO: FIX THAT!!
|
||||||
if(Type == DAT_STRUCT && CurrentToken.type == LI_SEMIC) {
|
if (Type == DAT_STRUCT && CurrentToken.type == LI_SEMIC) {
|
||||||
Tokenise();
|
Tokenise();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
VerifyToken(TY_IDENTIFIER, "ident");
|
VerifyToken(TY_IDENTIFIER, "ident");
|
||||||
|
|
||||||
if(FunctionComing && CurrentToken.type == LI_LPARE) {
|
if (FunctionComing && CurrentToken.type == LI_LPARE) {
|
||||||
printf("\tParsing function\n");
|
printf("\tParsing function\n");
|
||||||
Tree = ParseFunction(Type);
|
Tree = ParseFunction(Type);
|
||||||
if(Tree) {
|
if (Tree) {
|
||||||
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, 0);
|
AssembleTree(Tree, -1, 0);
|
||||||
FreeLocals();
|
FreeLocals();
|
||||||
|
@ -559,7 +556,7 @@ void ParseGlobals() {
|
||||||
BeginVariableDeclaration(Type, Composite, SC_GLOBAL);
|
BeginVariableDeclaration(Type, Composite, SC_GLOBAL);
|
||||||
VerifyToken(LI_SEMIC, ";");
|
VerifyToken(LI_SEMIC, ";");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int PointerTo(int Type) {
|
int PointerTo(int Type) {
|
||||||
if((Type & 0xf) == 0xf)
|
if ((Type & 0xf) == 0xf)
|
||||||
DieDecimal("Unrecognized type in pointerisation", Type);
|
DieDecimal("Unrecognized type in pointerisation", Type);
|
||||||
printf("\t\tPointerising a %s\n", TypeNames(Type));
|
printf("\t\tPointerising a %s\n", TypeNames(Type));
|
||||||
return (Type + 1);
|
return (Type + 1);
|
||||||
|
@ -52,7 +52,7 @@ int PointerTo(int Type) {
|
||||||
|
|
||||||
int ValueAt(int Type) {
|
int ValueAt(int Type) {
|
||||||
printf("\t\tDereferencing a %s\n", TypeNames(Type));
|
printf("\t\tDereferencing a %s\n", TypeNames(Type));
|
||||||
if((Type & 0xf) == 0x0)
|
if ((Type & 0xf) == 0x0)
|
||||||
DieDecimal("Unrecognized type in defererencing", Type);
|
DieDecimal("Unrecognized type in defererencing", Type);
|
||||||
return (Type - 1);
|
return (Type - 1);
|
||||||
}
|
}
|
||||||
|
@ -74,8 +74,8 @@ int ValueAt(int Type) {
|
||||||
int ParseOptionalPointer(struct SymbolTableEntry** Composite) {
|
int ParseOptionalPointer(struct SymbolTableEntry** Composite) {
|
||||||
|
|
||||||
int Type;
|
int Type;
|
||||||
|
|
||||||
switch(CurrentToken.type) {
|
switch (CurrentToken.type) {
|
||||||
case TY_VOID:
|
case TY_VOID:
|
||||||
Type = RET_VOID;
|
Type = RET_VOID;
|
||||||
Tokenise();
|
Tokenise();
|
||||||
|
@ -96,18 +96,18 @@ int ParseOptionalPointer(struct SymbolTableEntry** Composite) {
|
||||||
Type = DAT_STRUCT;
|
Type = DAT_STRUCT;
|
||||||
*Composite = BeginStructDeclaration();
|
*Composite = BeginStructDeclaration();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
DieDecimal("Illegal type for pointerisation", CurrentToken.type);
|
DieDecimal("Illegal type for pointerisation", CurrentToken.type);
|
||||||
}
|
}
|
||||||
// Recursively scan more *s
|
// Recursively scan more *s
|
||||||
// This makes things like:
|
// This makes things like:
|
||||||
// x = **y;
|
// x = **y;
|
||||||
// possible.
|
// possible.
|
||||||
while(1) {
|
while (1) {
|
||||||
printf("\t\t\tType on parsing is %d\n", CurrentToken.type);
|
printf("\t\t\tType on parsing is %d\n", CurrentToken.type);
|
||||||
if(CurrentToken.type != AR_STAR)
|
if (CurrentToken.type != AR_STAR)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
Type = PointerTo(Type);
|
Type = PointerTo(Type);
|
||||||
Tokenise();
|
Tokenise();
|
||||||
// Tokenise(); TODO: is this skipping pointers?
|
// Tokenise(); TODO: is this skipping pointers?
|
||||||
|
@ -129,13 +129,13 @@ int ParseOptionalPointer(struct SymbolTableEntry** Composite) {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct ASTNode* AccessArray() {
|
struct ASTNode* AccessArray() {
|
||||||
struct ASTNode* LeftNode, *RightNode;
|
struct ASTNode* LeftNode, * RightNode;
|
||||||
struct SymbolTableEntry* Entry;
|
struct SymbolTableEntry* Entry;
|
||||||
|
|
||||||
printf("\tAccessing array %s as requested\r\n", CurrentIdentifier);
|
printf("\tAccessing array %s as requested\r\n", CurrentIdentifier);
|
||||||
if ((Entry = FindSymbol(CurrentIdentifier)) == NULL || Entry->Structure != ST_ARR)
|
if ((Entry = FindSymbol(CurrentIdentifier)) == NULL || Entry->Structure != ST_ARR)
|
||||||
DieMessage("Accessing undeclared array", CurrentIdentifier);
|
DieMessage("Accessing undeclared array", CurrentIdentifier);
|
||||||
|
|
||||||
LeftNode = ConstructASTLeaf(OP_ADDRESS, Entry->Type, Entry, 0);
|
LeftNode = ConstructASTLeaf(OP_ADDRESS, Entry->Type, Entry, 0);
|
||||||
Tokenise();
|
Tokenise();
|
||||||
|
|
||||||
|
@ -143,10 +143,11 @@ struct ASTNode* AccessArray() {
|
||||||
|
|
||||||
VerifyToken(LI_RBRAS, "]");
|
VerifyToken(LI_RBRAS, "]");
|
||||||
|
|
||||||
if(!TypeIsInt(RightNode->ExprType))
|
if (!TypeIsInt(RightNode->ExprType))
|
||||||
Die("Array index is not integer");
|
Die("Array index is not integer");
|
||||||
|
|
||||||
printf("\t\tPreparing types - RightNode of type %s must be mutated to LeftNode type %s\r\n", (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);
|
RightNode = MutateType(RightNode, LeftNode->ExprType, OP_ADD);
|
||||||
|
|
||||||
LeftNode = ConstructASTNode(OP_ADD, Entry->Type, LeftNode, NULL, RightNode, NULL, 0);
|
LeftNode = ConstructASTNode(OP_ADD, Entry->Type, LeftNode, NULL, RightNode, NULL, 0);
|
||||||
|
@ -168,22 +169,22 @@ struct ASTNode* AccessArray() {
|
||||||
* @return the AST Node representing this statement.
|
* @return the AST Node representing this statement.
|
||||||
*/
|
*/
|
||||||
struct ASTNode* AccessMember(bool Deref) {
|
struct ASTNode* AccessMember(bool Deref) {
|
||||||
struct ASTNode* LeftNode, *RightNode;
|
struct ASTNode* LeftNode, * RightNode;
|
||||||
struct SymbolTableEntry* CompositeVar, *TypePtr, *Member;
|
struct SymbolTableEntry* CompositeVar, * TypePtr, * Member;
|
||||||
|
|
||||||
|
|
||||||
if((CompositeVar = FindSymbol(CurrentIdentifier)) == NULL)
|
if ((CompositeVar = FindSymbol(CurrentIdentifier)) == NULL)
|
||||||
DieMessage("Undecalred variable", CurrentIdentifier);
|
DieMessage("Undeclared variable", CurrentIdentifier);
|
||||||
if(Deref && CompositeVar->Type != PointerTo(DAT_STRUCT))
|
if (Deref && CompositeVar->Type != PointerTo(DAT_STRUCT))
|
||||||
DieMessage("Undeclared struct", CurrentIdentifier);
|
DieMessage("Undeclared struct", CurrentIdentifier);
|
||||||
if(!Deref && CompositeVar->Type != DAT_STRUCT)
|
if (!Deref && CompositeVar->Type != DAT_STRUCT)
|
||||||
DieMessage("Undeclared struct", CurrentIdentifier);
|
DieMessage("Undeclared struct", CurrentIdentifier);
|
||||||
|
|
||||||
if(Deref)
|
if (Deref)
|
||||||
LeftNode = ConstructASTLeaf(REF_IDENT, PointerTo(DAT_STRUCT), CompositeVar, 0);
|
LeftNode = ConstructASTLeaf(REF_IDENT, PointerTo(DAT_STRUCT), CompositeVar, 0);
|
||||||
else
|
else
|
||||||
LeftNode = ConstructASTLeaf(OP_ADDRESS, CompositeVar->Type, CompositeVar, 0);
|
LeftNode = ConstructASTLeaf(OP_ADDRESS, CompositeVar->Type, CompositeVar, 0);
|
||||||
|
|
||||||
LeftNode->RVal = true;
|
LeftNode->RVal = true;
|
||||||
|
|
||||||
TypePtr = CompositeVar->CompositeType;
|
TypePtr = CompositeVar->CompositeType;
|
||||||
|
@ -191,15 +192,16 @@ struct ASTNode* AccessMember(bool Deref) {
|
||||||
Tokenise();
|
Tokenise();
|
||||||
VerifyToken(TY_IDENTIFIER, "identifier");
|
VerifyToken(TY_IDENTIFIER, "identifier");
|
||||||
|
|
||||||
for(Member = TypePtr->Start; Member != NULL, Member = Member->NextSymbol;) {
|
for (Member = TypePtr->Start; Member != NULL; Member = Member->NextSymbol) {
|
||||||
printf("\tComparing struct entry %s with the wanted %s. Index %d.\r\n", Member->Name, CurrentIdentifier, Member->SinkOffset);
|
printf("\tComparing struct entry %s with the wanted %s. Index %d.\r\n", Member->Name, CurrentIdentifier,
|
||||||
if(!strcmp(Member->Name, CurrentIdentifier))
|
Member->SinkOffset);
|
||||||
|
if (!strcmp(Member->Name, CurrentIdentifier))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Member == NULL)
|
if (Member == NULL)
|
||||||
DieMessage("Invalid struct member", CurrentIdentifier);
|
DieMessage("Invalid struct member", CurrentIdentifier);
|
||||||
|
|
||||||
RightNode = ConstructASTLeaf(TERM_INTLITERAL, RET_INT, NULL, Member->SinkOffset);
|
RightNode = ConstructASTLeaf(TERM_INTLITERAL, RET_INT, NULL, Member->SinkOffset);
|
||||||
|
|
||||||
LeftNode = ConstructASTNode(OP_ADD, PointerTo(Member->Type), LeftNode, NULL, RightNode, NULL, 0);
|
LeftNode = ConstructASTNode(OP_ADD, PointerTo(Member->Type), LeftNode, NULL, RightNode, NULL, 0);
|
||||||
|
|
144
src/Statements.c
144
src/Statements.c
|
@ -28,34 +28,34 @@
|
||||||
|
|
||||||
static int ReadDeclarationList(struct SymbolTableEntry* FunctionSymbol, int Storage, int End) {
|
static int ReadDeclarationList(struct SymbolTableEntry* FunctionSymbol, int Storage, int End) {
|
||||||
int TokenType, ParamCount = 0;
|
int TokenType, ParamCount = 0;
|
||||||
struct SymbolTableEntry* PrototypePointer = NULL, *Composite;
|
struct SymbolTableEntry* PrototypePointer = NULL, * Composite;
|
||||||
|
|
||||||
if(FunctionSymbol != NULL)
|
if (FunctionSymbol != NULL)
|
||||||
PrototypePointer = FunctionSymbol->Start;
|
PrototypePointer = FunctionSymbol->Start;
|
||||||
|
|
||||||
while(CurrentToken.type != End) {
|
while (CurrentToken.type != End) {
|
||||||
TokenType = ParseOptionalPointer(&Composite);
|
TokenType = ParseOptionalPointer(&Composite);
|
||||||
VerifyToken(TY_IDENTIFIER, "identifier");
|
VerifyToken(TY_IDENTIFIER, "identifier");
|
||||||
|
|
||||||
printf("\tReading a new element: %s of type %d, scope %s\n", CurrentIdentifier, TokenType, ScopeNames[Storage]);
|
printf("\tReading a new element: %s of type %d, scope %s\n", CurrentIdentifier, TokenType, ScopeNames[Storage]);
|
||||||
|
|
||||||
if(PrototypePointer != NULL) {
|
if (PrototypePointer != NULL) {
|
||||||
if(TokenType != PrototypePointer->Type)
|
if (TokenType != PrototypePointer->Type)
|
||||||
DieDecimal("Function parameter of invalid type at index", ParamCount + 1);
|
DieDecimal("Function parameter of invalid type at index", ParamCount + 1);
|
||||||
PrototypePointer=PrototypePointer->NextSymbol;
|
PrototypePointer = PrototypePointer->NextSymbol;
|
||||||
} else {
|
} else {
|
||||||
BeginVariableDeclaration(TokenType, Composite, Storage);
|
BeginVariableDeclaration(TokenType, Composite, Storage);
|
||||||
}
|
}
|
||||||
ParamCount++;
|
ParamCount++;
|
||||||
|
|
||||||
if((CurrentToken.type != LI_COM) && (CurrentToken.type != End))
|
if ((CurrentToken.type != LI_COM) && (CurrentToken.type != End))
|
||||||
DieDecimal("Unexpected token in parameter", CurrentToken.type);
|
DieDecimal("Unexpected token in parameter", CurrentToken.type);
|
||||||
|
|
||||||
if(CurrentToken.type == LI_COM)
|
if (CurrentToken.type == LI_COM)
|
||||||
Tokenise();
|
Tokenise();
|
||||||
}
|
}
|
||||||
|
|
||||||
if((FunctionSymbol != NULL) && (ParamCount != FunctionSymbol->Length))
|
if ((FunctionSymbol != NULL) && (ParamCount != FunctionSymbol->Length))
|
||||||
DieMessage("Invalid number of parameters in prototyped function", FunctionSymbol->Name);
|
DieMessage("Invalid number of parameters in prototyped function", FunctionSymbol->Name);
|
||||||
|
|
||||||
return ParamCount;
|
return ParamCount;
|
||||||
|
@ -74,23 +74,23 @@ static int ReadDeclarationList(struct SymbolTableEntry* FunctionSymbol, int Stor
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct SymbolTableEntry* BeginStructDeclaration() {
|
struct SymbolTableEntry* BeginStructDeclaration() {
|
||||||
struct SymbolTableEntry* Composite = NULL, *Member;
|
struct SymbolTableEntry* Composite = NULL, * Member;
|
||||||
int Offset;
|
int Offset;
|
||||||
|
|
||||||
Tokenise();
|
Tokenise();
|
||||||
|
|
||||||
if(CurrentToken.type == TY_IDENTIFIER) {
|
if (CurrentToken.type == TY_IDENTIFIER) {
|
||||||
Composite = FindStruct(CurrentIdentifier);
|
Composite = FindStruct(CurrentIdentifier);
|
||||||
Tokenise();
|
Tokenise();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(CurrentToken.type != LI_LBRAC) {
|
if (CurrentToken.type != LI_LBRAC) {
|
||||||
if(Composite == NULL)
|
if (Composite == NULL)
|
||||||
DieMessage("Unknown Struct", CurrentIdentifier);
|
DieMessage("Unknown Struct", CurrentIdentifier);
|
||||||
return Composite;
|
return Composite;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Composite)
|
if (Composite)
|
||||||
DieMessage("Redefinition of struct", CurrentIdentifier);
|
DieMessage("Redefinition of struct", CurrentIdentifier);
|
||||||
|
|
||||||
Composite = AddSymbol(CurrentIdentifier, DAT_STRUCT, 0, SC_STRUCT, 0, 0, NULL);
|
Composite = AddSymbol(CurrentIdentifier, DAT_STRUCT, 0, SC_STRUCT, 0, 0, NULL);
|
||||||
|
@ -107,7 +107,7 @@ struct SymbolTableEntry* BeginStructDeclaration() {
|
||||||
Member->SinkOffset = 0;
|
Member->SinkOffset = 0;
|
||||||
Offset = TypeSize(Member->Type, Member->CompositeType);
|
Offset = TypeSize(Member->Type, Member->CompositeType);
|
||||||
|
|
||||||
for(Member = Member->NextSymbol; Member != NULL; Member = Member->NextSymbol) {
|
for (Member = Member->NextSymbol; Member != NULL; Member = Member->NextSymbol) {
|
||||||
Member->SinkOffset = AsAlignMemory(Member->Type, Offset, 1);
|
Member->SinkOffset = AsAlignMemory(Member->Type, Offset, 1);
|
||||||
|
|
||||||
Offset += TypeSize(Member->Type, Member->CompositeType);
|
Offset += TypeSize(Member->Type, Member->CompositeType);
|
||||||
|
@ -132,24 +132,24 @@ struct SymbolTableEntry* BeginStructDeclaration() {
|
||||||
struct SymbolTableEntry* BeginVariableDeclaration(int Type, struct SymbolTableEntry* Composite, int Scope) {
|
struct SymbolTableEntry* BeginVariableDeclaration(int Type, struct SymbolTableEntry* Composite, int Scope) {
|
||||||
struct SymbolTableEntry* Symbol = NULL;
|
struct SymbolTableEntry* Symbol = NULL;
|
||||||
|
|
||||||
switch(Scope) {
|
switch (Scope) {
|
||||||
case SC_GLOBAL:
|
case SC_GLOBAL:
|
||||||
if(FindGlobal(CurrentIdentifier) != NULL)
|
if (FindGlobal(CurrentIdentifier) != NULL)
|
||||||
DieMessage("Invalid redeclaration of global variable", CurrentIdentifier);
|
DieMessage("Invalid redeclaration of global variable", CurrentIdentifier);
|
||||||
case SC_LOCAL:
|
case SC_LOCAL:
|
||||||
case SC_PARAM:
|
case SC_PARAM:
|
||||||
if(FindLocal(CurrentIdentifier) != NULL)
|
if (FindLocal(CurrentIdentifier) != NULL)
|
||||||
DieMessage("Invalid redeclaration of local variable", CurrentIdentifier);
|
DieMessage("Invalid redeclaration of local variable", CurrentIdentifier);
|
||||||
case SC_MEMBER:
|
case SC_MEMBER:
|
||||||
if(FindMember(CurrentIdentifier) != NULL)
|
if (FindMember(CurrentIdentifier) != NULL)
|
||||||
DieMessage("Invalid redeclaration of Enum/Struct member", CurrentIdentifier);
|
DieMessage("Invalid redeclaration of Enum/Struct member", CurrentIdentifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(CurrentToken.type == LI_LBRAS) {
|
if (CurrentToken.type == LI_LBRAS) {
|
||||||
Tokenise();
|
Tokenise();
|
||||||
|
|
||||||
if(CurrentToken.type == LI_INT) {
|
if (CurrentToken.type == LI_INT) {
|
||||||
switch(Scope) {
|
switch (Scope) {
|
||||||
case SC_GLOBAL:
|
case SC_GLOBAL:
|
||||||
Symbol = AddSymbol(CurrentIdentifier, PointerTo(Type), ST_ARR, Scope, 1, 0, NULL);
|
Symbol = AddSymbol(CurrentIdentifier, PointerTo(Type), ST_ARR, Scope, 1, 0, NULL);
|
||||||
break;
|
break;
|
||||||
|
@ -186,13 +186,13 @@ struct SymbolTableEntry* BeginVariableDeclaration(int Type, struct SymbolTableEn
|
||||||
struct ASTNode* ParseFunction(int Type) {
|
struct ASTNode* ParseFunction(int Type) {
|
||||||
struct ASTNode* Tree;
|
struct ASTNode* Tree;
|
||||||
struct ASTNode* FinalStatement;
|
struct ASTNode* FinalStatement;
|
||||||
struct SymbolTableEntry* OldFunction, *NewFunction = NULL;
|
struct SymbolTableEntry* OldFunction, * NewFunction = NULL;
|
||||||
int SymbolSlot, BreakLabel, ParamCount, ID;
|
int SymbolSlot, BreakLabel, ParamCount, ID;
|
||||||
|
|
||||||
if((OldFunction = FindSymbol(CurrentIdentifier)) != NULL)
|
if ((OldFunction = FindSymbol(CurrentIdentifier)) != NULL)
|
||||||
if(OldFunction->Storage != ST_FUNC)
|
if (OldFunction->Storage != ST_FUNC)
|
||||||
OldFunction = NULL;
|
OldFunction = NULL;
|
||||||
if(OldFunction == NULL) {
|
if (OldFunction == NULL) {
|
||||||
BreakLabel = NewLabel();
|
BreakLabel = NewLabel();
|
||||||
NewFunction = AddSymbol(CurrentIdentifier, Type, ST_FUNC, SC_GLOBAL, BreakLabel, 0, NULL);
|
NewFunction = AddSymbol(CurrentIdentifier, Type, ST_FUNC, SC_GLOBAL, BreakLabel, 0, NULL);
|
||||||
}
|
}
|
||||||
|
@ -201,12 +201,12 @@ struct ASTNode* ParseFunction(int Type) {
|
||||||
ParamCount = ReadDeclarationList(OldFunction, SC_PARAM, LI_RPARE);
|
ParamCount = ReadDeclarationList(OldFunction, SC_PARAM, LI_RPARE);
|
||||||
VerifyToken(LI_RPARE, ")");
|
VerifyToken(LI_RPARE, ")");
|
||||||
|
|
||||||
printf("\nIdentified%sfunction %s of return type %s, end label %d\n",
|
printf("\nIdentified%sfunction %s of return type %s, end label %d\n",
|
||||||
(OldFunction == NULL) ? " new " : " overloaded ",
|
(OldFunction == NULL) ? " new " : " overloaded ",
|
||||||
(OldFunction == NULL) ? NewFunction->Name : OldFunction->Name,
|
(OldFunction == NULL) ? NewFunction->Name : OldFunction->Name,
|
||||||
TypeNames(Type), BreakLabel);
|
TypeNames(Type), BreakLabel);
|
||||||
|
|
||||||
if(NewFunction) {
|
if (NewFunction) {
|
||||||
NewFunction->Elements = ParamCount;
|
NewFunction->Elements = ParamCount;
|
||||||
NewFunction->Start = Params;
|
NewFunction->Start = Params;
|
||||||
NewFunction->Type = RET_LONG;
|
NewFunction->Type = RET_LONG;
|
||||||
|
@ -215,7 +215,7 @@ struct ASTNode* ParseFunction(int Type) {
|
||||||
|
|
||||||
Params = ParamsEnd = NULL;
|
Params = ParamsEnd = NULL;
|
||||||
|
|
||||||
if(CurrentToken.type == LI_SEMIC) {
|
if (CurrentToken.type == LI_SEMIC) {
|
||||||
Tokenise();
|
Tokenise();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -224,11 +224,11 @@ struct ASTNode* ParseFunction(int Type) {
|
||||||
|
|
||||||
Tree = ParseCompound();
|
Tree = ParseCompound();
|
||||||
|
|
||||||
if(Type != RET_VOID) {
|
if (Type != RET_VOID) {
|
||||||
// Functions with one statement have no composite node, so we have to check
|
// Functions with one statement have no composite node, so we have to check
|
||||||
FinalStatement = (Tree->Operation == OP_COMP) ? Tree->Right : Tree;
|
FinalStatement = (Tree->Operation == OP_COMP) ? Tree->Right : Tree;
|
||||||
|
|
||||||
if(FinalStatement == NULL || FinalStatement->Operation != OP_RET) {
|
if (FinalStatement == NULL || FinalStatement->Operation != OP_RET) {
|
||||||
Die("Function with non-void type does not return");
|
Die("Function with non-void type does not return");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,9 +249,9 @@ struct ASTNode* ReturnStatement() {
|
||||||
int ReturnType;
|
int ReturnType;
|
||||||
|
|
||||||
|
|
||||||
if(FunctionEntry->Type == RET_VOID)
|
if (FunctionEntry->Type == RET_VOID)
|
||||||
Die("Attempt to return from void function");
|
Die("Attempt to return from void function");
|
||||||
|
|
||||||
VerifyToken(KW_RETURN, "return");
|
VerifyToken(KW_RETURN, "return");
|
||||||
|
|
||||||
VerifyToken(LI_LPARE, "("); // TODO: Make optional! Reject?
|
VerifyToken(LI_LPARE, "("); // TODO: Make optional! Reject?
|
||||||
|
@ -259,9 +259,9 @@ struct ASTNode* ReturnStatement() {
|
||||||
Tree = ParsePrecedenceASTNode(0);
|
Tree = ParsePrecedenceASTNode(0);
|
||||||
|
|
||||||
Tree = MutateType(Tree, FunctionEntry->Type, 0);
|
Tree = MutateType(Tree, FunctionEntry->Type, 0);
|
||||||
if(Tree == NULL)
|
if (Tree == NULL)
|
||||||
Die("Returning a value of incorrect type for function");
|
Die("Returning a value of incorrect type for function");
|
||||||
|
|
||||||
|
|
||||||
Tree = ConstructASTBranch(OP_RET, RET_NONE, Tree, FunctionEntry, 0);
|
Tree = ConstructASTBranch(OP_RET, RET_NONE, Tree, FunctionEntry, 0);
|
||||||
|
|
||||||
|
@ -273,7 +273,6 @@ struct ASTNode* ReturnStatement() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Handles the surrounding logic for If statements.
|
* Handles the surrounding logic for If statements.
|
||||||
*
|
*
|
||||||
|
@ -300,7 +299,7 @@ struct ASTNode* ReturnStatement() {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
struct ASTNode* IfStatement() {
|
struct ASTNode* IfStatement() {
|
||||||
struct ASTNode* Condition, *True, *False = NULL;
|
struct ASTNode* Condition, * True, * False = NULL;
|
||||||
|
|
||||||
VerifyToken(KW_IF, "if");
|
VerifyToken(KW_IF, "if");
|
||||||
VerifyToken(LI_LPARE, "(");
|
VerifyToken(LI_LPARE, "(");
|
||||||
|
@ -310,14 +309,14 @@ struct ASTNode* IfStatement() {
|
||||||
// Limit if(x) to =? != < > <= =>
|
// Limit if(x) to =? != < > <= =>
|
||||||
// No null checking, no arithmetic, no functions.
|
// No null checking, no arithmetic, no functions.
|
||||||
// TODO: this
|
// TODO: this
|
||||||
if(Condition->Operation < OP_EQUAL || Condition->Operation > OP_GREATE)
|
if (Condition->Operation < OP_EQUAL || Condition->Operation > OP_GREATE)
|
||||||
Condition = ConstructASTBranch(OP_BOOLCONV, Condition->ExprType, Condition, NULL, 0);
|
Condition = ConstructASTBranch(OP_BOOLCONV, Condition->ExprType, Condition, NULL, 0);
|
||||||
|
|
||||||
VerifyToken(LI_RPARE, ")");
|
VerifyToken(LI_RPARE, ")");
|
||||||
|
|
||||||
True = ParseCompound();
|
True = ParseCompound();
|
||||||
|
|
||||||
if(CurrentToken.type == KW_ELSE) {
|
if (CurrentToken.type == KW_ELSE) {
|
||||||
Tokenise();
|
Tokenise();
|
||||||
False = ParseCompound();
|
False = ParseCompound();
|
||||||
}
|
}
|
||||||
|
@ -352,7 +351,7 @@ struct ASTNode* IfStatement() {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
struct ASTNode* WhileStatement() {
|
struct ASTNode* WhileStatement() {
|
||||||
struct ASTNode* Condition, *Body;
|
struct ASTNode* Condition, * Body;
|
||||||
|
|
||||||
VerifyToken(KW_WHILE, "while");
|
VerifyToken(KW_WHILE, "while");
|
||||||
VerifyToken(LI_LPARE, "(");
|
VerifyToken(LI_LPARE, "(");
|
||||||
|
@ -360,9 +359,9 @@ struct ASTNode* WhileStatement() {
|
||||||
Condition = ParsePrecedenceASTNode(0);
|
Condition = ParsePrecedenceASTNode(0);
|
||||||
|
|
||||||
|
|
||||||
if(Condition->Operation < OP_EQUAL || Condition->Operation > OP_GREATE)
|
if (Condition->Operation < OP_EQUAL || Condition->Operation > OP_GREATE)
|
||||||
Condition = ConstructASTBranch(OP_BOOLCONV, Condition->ExprType, Condition, NULL, 0);
|
Condition = ConstructASTBranch(OP_BOOLCONV, Condition->ExprType, Condition, NULL, 0);
|
||||||
|
|
||||||
VerifyToken(LI_RPARE, ")");
|
VerifyToken(LI_RPARE, ")");
|
||||||
|
|
||||||
Body = ParseCompound();
|
Body = ParseCompound();
|
||||||
|
@ -400,8 +399,8 @@ struct ASTNode* WhileStatement() {
|
||||||
* @return the AST of this statement
|
* @return the AST of this statement
|
||||||
*/
|
*/
|
||||||
struct ASTNode* ForStatement() {
|
struct ASTNode* ForStatement() {
|
||||||
struct ASTNode* Condition, *Body;
|
struct ASTNode* Condition, * Body;
|
||||||
struct ASTNode* Preop, *Postop;
|
struct ASTNode* Preop, * Postop;
|
||||||
|
|
||||||
struct ASTNode* Tree;
|
struct ASTNode* Tree;
|
||||||
|
|
||||||
|
@ -413,7 +412,7 @@ struct ASTNode* ForStatement() {
|
||||||
|
|
||||||
Condition = ParsePrecedenceASTNode(0);
|
Condition = ParsePrecedenceASTNode(0);
|
||||||
|
|
||||||
if(Condition->Operation < OP_EQUAL || Condition->Operation > OP_GREATE)
|
if (Condition->Operation < OP_EQUAL || Condition->Operation > OP_GREATE)
|
||||||
Condition = ConstructASTBranch(OP_BOOLCONV, Condition->ExprType, Condition, NULL, 0);
|
Condition = ConstructASTBranch(OP_BOOLCONV, Condition->ExprType, Condition, NULL, 0);
|
||||||
|
|
||||||
VerifyToken(LI_SEMIC, ";");
|
VerifyToken(LI_SEMIC, ";");
|
||||||
|
@ -438,7 +437,7 @@ struct ASTNode* ForStatement() {
|
||||||
* Handles the surrounding logic for the Print statement.
|
* Handles the surrounding logic for the Print statement.
|
||||||
*
|
*
|
||||||
* This is a legacy hold-over from the early testing, and it
|
* This is a legacy hold-over from the early testing, and it
|
||||||
* serves merely as a wrapper around the cstdlib printf function.
|
* serves merely as a wrapper around the cstdlib printf.er function.
|
||||||
*
|
*
|
||||||
* It does, however (//TODO), attempt to guess the type that you
|
* It does, however (//TODO), attempt to guess the type that you
|
||||||
* want to print, which takes a lot of the guesswork out of printing.
|
* want to print, which takes a lot of the guesswork out of printing.
|
||||||
|
@ -457,18 +456,18 @@ struct ASTNode* PrintStatement(void) {
|
||||||
RightType = Tree->ExprType;
|
RightType = Tree->ExprType;
|
||||||
|
|
||||||
Tree = MutateType(Tree, RightType, 0);
|
Tree = MutateType(Tree, RightType, 0);
|
||||||
if(!Tree)
|
if (!Tree)
|
||||||
DieDecimal("Attempting to print an invalid type:", RightType);
|
DieDecimal("Attempting to print an invalid type:", RightType);
|
||||||
|
|
||||||
if(RightType)
|
if (RightType)
|
||||||
Tree = ConstructASTBranch(Tree->Right->Operation, RET_INT, Tree, NULL, 0);
|
Tree = ConstructASTBranch(Tree->Right->Operation, RET_INT, Tree, NULL, 0);
|
||||||
|
|
||||||
Tree = ConstructASTBranch(OP_PRINT, RET_NONE, Tree, NULL, 0);
|
Tree = ConstructASTBranch(OP_PRINT, RET_NONE, Tree, NULL, 0);
|
||||||
|
|
||||||
//ParseAST(Tree);
|
//ParseAST(Tree);
|
||||||
|
|
||||||
return Tree;
|
return Tree;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -498,25 +497,26 @@ struct ASTNode* PostfixStatement() {
|
||||||
struct SymbolTableEntry* Entry;
|
struct SymbolTableEntry* Entry;
|
||||||
|
|
||||||
Tokenise();
|
Tokenise();
|
||||||
|
|
||||||
if(CurrentToken.type == LI_LPARE)
|
if (CurrentToken.type == LI_LPARE)
|
||||||
return CallFunction();
|
return CallFunction();
|
||||||
|
|
||||||
if(CurrentToken.type == LI_LBRAS)
|
if (CurrentToken.type == LI_LBRAS)
|
||||||
return AccessArray();
|
return AccessArray();
|
||||||
|
|
||||||
// If we get here, we must be a variable.
|
// If we get here, we must be a variable.
|
||||||
// (as functions have been called and arrays have been indexed)
|
// (as functions have been called and arrays have been indexed)
|
||||||
// Check that the variable is recognized..
|
// Check that the variable is recognized..
|
||||||
|
|
||||||
if((Entry = FindSymbol(CurrentIdentifier)) == NULL || (Entry->Structure != ST_VAR && Entry->Structure != ST_FUNC)) {
|
if ((Entry = FindSymbol(CurrentIdentifier)) == NULL ||
|
||||||
|
(Entry->Structure != ST_VAR && Entry->Structure != ST_FUNC)) {
|
||||||
DumpAllLists();
|
DumpAllLists();
|
||||||
DieMessage("Unknown Variable", CurrentIdentifier);
|
DieMessage("Unknown Variable", CurrentIdentifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Here we check for postincrement and postdecrement.
|
// Here we check for postincrement and postdecrement.
|
||||||
|
|
||||||
switch(CurrentToken.type) {
|
switch (CurrentToken.type) {
|
||||||
case LI_DOT:
|
case LI_DOT:
|
||||||
return AccessMember(false);
|
return AccessMember(false);
|
||||||
case LI_ARROW:
|
case LI_ARROW:
|
||||||
|
@ -534,7 +534,7 @@ struct ASTNode* PostfixStatement() {
|
||||||
}
|
}
|
||||||
|
|
||||||
return Tree;
|
return Tree;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -579,11 +579,11 @@ struct ASTNode* PrefixStatement() {
|
||||||
Tree->RVal = 1;
|
Tree->RVal = 1;
|
||||||
Tree = ConstructASTBranch(OP_BITNOT, Tree->ExprType, Tree, NULL, 0);
|
Tree = ConstructASTBranch(OP_BITNOT, Tree->ExprType, Tree, NULL, 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AR_MINUS:
|
case AR_MINUS:
|
||||||
Tokenise();
|
Tokenise();
|
||||||
Tree = PrefixStatement();
|
Tree = PrefixStatement();
|
||||||
|
|
||||||
Tree = ConstructASTBranch(OP_NEGATE, Tree->ExprType, Tree, NULL, 0);
|
Tree = ConstructASTBranch(OP_NEGATE, Tree->ExprType, Tree, NULL, 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -591,7 +591,7 @@ struct ASTNode* PrefixStatement() {
|
||||||
Tokenise();
|
Tokenise();
|
||||||
Tree = PrefixStatement();
|
Tree = PrefixStatement();
|
||||||
|
|
||||||
if(Tree->Operation != REF_IDENT)
|
if (Tree->Operation != REF_IDENT)
|
||||||
Die("++ not followed by identifier");
|
Die("++ not followed by identifier");
|
||||||
Tree = ConstructASTBranch(OP_PREINC, Tree->ExprType, Tree, NULL, 0);
|
Tree = ConstructASTBranch(OP_PREINC, Tree->ExprType, Tree, NULL, 0);
|
||||||
break;
|
break;
|
||||||
|
@ -600,9 +600,9 @@ struct ASTNode* PrefixStatement() {
|
||||||
Tokenise();
|
Tokenise();
|
||||||
Tree = PrefixStatement();
|
Tree = PrefixStatement();
|
||||||
|
|
||||||
if(Tree->Operation != REF_IDENT)
|
if (Tree->Operation != REF_IDENT)
|
||||||
Die("-- not followed by identifier");
|
Die("-- not followed by identifier");
|
||||||
|
|
||||||
Tree = ConstructASTBranch(OP_PREDEC, Tree->ExprType, Tree, NULL, 0);
|
Tree = ConstructASTBranch(OP_PREDEC, Tree->ExprType, Tree, NULL, 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -614,7 +614,7 @@ struct ASTNode* PrefixStatement() {
|
||||||
// We need to recursively parse prefixes;
|
// We need to recursively parse prefixes;
|
||||||
Tree = PrefixStatement();
|
Tree = PrefixStatement();
|
||||||
|
|
||||||
if(Tree->Operation != REF_IDENT)
|
if (Tree->Operation != REF_IDENT)
|
||||||
Die("& must be followed by another & or an identifier.");
|
Die("& must be followed by another & or an identifier.");
|
||||||
|
|
||||||
Tree->Operation = OP_ADDRESS;
|
Tree->Operation = OP_ADDRESS;
|
||||||
|
@ -625,7 +625,7 @@ struct ASTNode* PrefixStatement() {
|
||||||
|
|
||||||
Tree = PrefixStatement();
|
Tree = PrefixStatement();
|
||||||
|
|
||||||
if(Tree->Operation != REF_IDENT && Tree->Operation != OP_DEREF)
|
if (Tree->Operation != REF_IDENT && Tree->Operation != OP_DEREF)
|
||||||
Die("* must be followed by another * or an identifier.");
|
Die("* must be followed by another * or an identifier.");
|
||||||
|
|
||||||
Tree = ConstructASTBranch(OP_DEREF, ValueAt(Tree->ExprType), Tree, NULL, 0);
|
Tree = ConstructASTBranch(OP_DEREF, ValueAt(Tree->ExprType), Tree, NULL, 0);
|
||||||
|
@ -633,7 +633,7 @@ struct ASTNode* PrefixStatement() {
|
||||||
|
|
||||||
default:
|
default:
|
||||||
Tree = ParsePrimary();
|
Tree = ParsePrimary();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Tree;
|
return Tree;
|
||||||
|
|
|
@ -17,7 +17,7 @@ void DumpAllLists() {
|
||||||
printf("\nLocal symbols:\n");
|
printf("\nLocal symbols:\n");
|
||||||
DumpList(Locals);
|
DumpList(Locals);
|
||||||
printf("\nParameters:\n");
|
printf("\nParameters:\n");
|
||||||
if(FunctionEntry != NULL && FunctionEntry->Start != NULL)
|
if (FunctionEntry != NULL && FunctionEntry->Start != NULL)
|
||||||
DumpList(FunctionEntry->Start);
|
DumpList(FunctionEntry->Start);
|
||||||
DumpList(Params);
|
DumpList(Params);
|
||||||
printf("\nStructs:\n");
|
printf("\nStructs:\n");
|
||||||
|
@ -32,8 +32,8 @@ void DumpAllLists() {
|
||||||
* @param List the list to dump
|
* @param List the list to dump
|
||||||
*/
|
*/
|
||||||
void DumpList(struct SymbolTableEntry* List) {
|
void DumpList(struct SymbolTableEntry* List) {
|
||||||
for(; List != NULL; List = List->NextSymbol)
|
for (; List != NULL; List = List->NextSymbol)
|
||||||
if((List->Name != NULL))
|
if ((List->Name != NULL))
|
||||||
printf("%s\t", List->Name);
|
printf("%s\t", List->Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,8 +47,8 @@ void DumpList(struct SymbolTableEntry* List) {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static struct SymbolTableEntry* SearchList(char* Name, struct SymbolTableEntry* List) {
|
static struct SymbolTableEntry* SearchList(char* Name, struct SymbolTableEntry* List) {
|
||||||
for(; List != NULL; List = List->NextSymbol)
|
for (; List != NULL; List = List->NextSymbol)
|
||||||
if((List->Name != NULL) && !strcmp(Name, List->Name))
|
if ((List->Name != NULL) && !strcmp(Name, List->Name))
|
||||||
return (List);
|
return (List);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -67,17 +67,17 @@ static struct SymbolTableEntry* SearchList(char* Name, struct SymbolTableEntry*
|
||||||
struct SymbolTableEntry* FindSymbol(char* Symbol) {
|
struct SymbolTableEntry* FindSymbol(char* Symbol) {
|
||||||
struct SymbolTableEntry* Node;
|
struct SymbolTableEntry* Node;
|
||||||
|
|
||||||
if(FunctionEntry) {
|
if (FunctionEntry) {
|
||||||
Node = SearchList(Symbol, FunctionEntry->Start);
|
Node = SearchList(Symbol, FunctionEntry->Start);
|
||||||
if(Node)
|
if (Node)
|
||||||
return Node;
|
return Node;
|
||||||
}
|
}
|
||||||
|
|
||||||
Node = SearchList(Symbol, Locals);
|
Node = SearchList(Symbol, Locals);
|
||||||
if(Node)
|
if (Node)
|
||||||
return Node;
|
return Node;
|
||||||
|
|
||||||
|
|
||||||
return SearchList(Symbol, Globals);
|
return SearchList(Symbol, Globals);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,9 +90,9 @@ struct SymbolTableEntry* FindSymbol(char* Symbol) {
|
||||||
struct SymbolTableEntry* FindLocal(char* Symbol) {
|
struct SymbolTableEntry* FindLocal(char* Symbol) {
|
||||||
struct SymbolTableEntry* Node;
|
struct SymbolTableEntry* Node;
|
||||||
|
|
||||||
if(FunctionEntry) {
|
if (FunctionEntry) {
|
||||||
Node = SearchList(Symbol, FunctionEntry->Start);
|
Node = SearchList(Symbol, FunctionEntry->Start);
|
||||||
if(Node)
|
if (Node)
|
||||||
return Node;
|
return Node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,10 +145,10 @@ struct SymbolTableEntry* FindMember(char* Symbol) {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void AppendSymbol(struct SymbolTableEntry** Head, struct SymbolTableEntry** Tail, struct SymbolTableEntry* Node) {
|
void AppendSymbol(struct SymbolTableEntry** Head, struct SymbolTableEntry** Tail, struct SymbolTableEntry* Node) {
|
||||||
if(Head == NULL || Tail == NULL || Node == NULL)
|
if (Head == NULL || Tail == NULL || Node == NULL)
|
||||||
Die("Not enough data to append a symbol to the tables");
|
Die("Not enough data to append a symbol to the tables");
|
||||||
|
|
||||||
if(*Tail) {
|
if (*Tail) {
|
||||||
(*Tail)->NextSymbol = Node;
|
(*Tail)->NextSymbol = Node;
|
||||||
*Tail = Node;
|
*Tail = Node;
|
||||||
} else {
|
} else {
|
||||||
|
@ -193,10 +193,11 @@ void ClearTables() {
|
||||||
*
|
*
|
||||||
* @return The SymbolTableEntry* pointer that corresponds to this newly constructed node.
|
* @return The SymbolTableEntry* pointer that corresponds to this newly constructed node.
|
||||||
*/
|
*/
|
||||||
struct SymbolTableEntry* AddSymbol(char* Name, int Type, int Structure, int Storage, int Length, int SinkOffset, struct SymbolTableEntry* CompositeType) {
|
struct SymbolTableEntry* AddSymbol(char* Name, int Type, int Structure, int Storage, int Length, int SinkOffset,
|
||||||
|
struct SymbolTableEntry* CompositeType) {
|
||||||
|
|
||||||
struct SymbolTableEntry* Node =
|
struct SymbolTableEntry* Node =
|
||||||
(struct SymbolTableEntry*) malloc(sizeof(struct SymbolTableEntry));
|
(struct SymbolTableEntry*) malloc(sizeof(struct SymbolTableEntry));
|
||||||
|
|
||||||
Node->Name = strdup(Name);
|
Node->Name = strdup(Name);
|
||||||
Node->Type = Type;
|
Node->Type = Type;
|
||||||
|
@ -206,12 +207,13 @@ struct SymbolTableEntry* AddSymbol(char* Name, int Type, int Structure, int Stor
|
||||||
Node->SinkOffset = SinkOffset;
|
Node->SinkOffset = SinkOffset;
|
||||||
Node->CompositeType = CompositeType;
|
Node->CompositeType = CompositeType;
|
||||||
|
|
||||||
printf("Adding a %s symbol of name %s, type %s to the tables.\n", ScopeNames[Node->Storage], Node->Name, TypeNames(Node->Type));
|
printf("Adding a %s symbol of name %s, type %s to the tables.\n", ScopeNames[Node->Storage], Node->Name,
|
||||||
switch(Storage) {
|
TypeNames(Node->Type));
|
||||||
|
switch (Storage) {
|
||||||
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) AsGlobalSymbol(Node);
|
||||||
break;
|
break;
|
||||||
case SC_STRUCT:
|
case SC_STRUCT:
|
||||||
AppendSymbol(&Structs, &StructsEnd, Node);
|
AppendSymbol(&Structs, &StructsEnd, Node);
|
||||||
|
@ -224,9 +226,9 @@ struct SymbolTableEntry* AddSymbol(char* Name, int Type, int Structure, int Stor
|
||||||
case SC_PARAM:
|
case SC_PARAM:
|
||||||
AppendSymbol(&Params, &ParamsEnd, Node);
|
AppendSymbol(&Params, &ParamsEnd, Node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return Node;
|
return Node;
|
||||||
}
|
}
|
76
src/Types.c
76
src/Types.c
|
@ -41,13 +41,16 @@ int TypeIsPtr(int Type) {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int PrimitiveSize(int Type) {
|
int PrimitiveSize(int Type) {
|
||||||
|
|
||||||
if(TypeIsPtr(Type)) return 8;
|
if (TypeIsPtr(Type)) return 8;
|
||||||
switch(Type) {
|
switch (Type) {
|
||||||
case RET_CHAR: return 1;
|
case RET_CHAR:
|
||||||
case RET_INT: return 4;
|
return 1;
|
||||||
case RET_LONG: return 8;
|
case RET_INT:
|
||||||
default:
|
return 4;
|
||||||
|
case RET_LONG:
|
||||||
|
return 8;
|
||||||
|
default:
|
||||||
DieBinary("Bad type in PrimitiveSize", Type);
|
DieBinary("Bad type in PrimitiveSize", Type);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -61,7 +64,7 @@ int PrimitiveSize(int Type) {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int TypeSize(int Type, struct SymbolTableEntry* Composite) {
|
int TypeSize(int Type, struct SymbolTableEntry* Composite) {
|
||||||
if(Type == DAT_STRUCT) return Composite->Length;
|
if (Type == DAT_STRUCT) return Composite->Length;
|
||||||
return PrimitiveSize(Type);
|
return PrimitiveSize(Type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,17 +79,26 @@ static char TypeBuffer[7];
|
||||||
* Get the name of the input Type as a string.
|
* Get the name of the input Type as a string.
|
||||||
*/
|
*/
|
||||||
char* TypeNames(int Type) {
|
char* TypeNames(int Type) {
|
||||||
switch(Type) {
|
switch (Type) {
|
||||||
case RET_CHAR: memcpy(TypeBuffer, "Char", 4); break;
|
case RET_CHAR:
|
||||||
case RET_INT: memcpy(TypeBuffer, "Int ", 4); break;
|
memcpy(TypeBuffer, "Char", 4);
|
||||||
case RET_LONG: memcpy(TypeBuffer, "Long", 4); break;
|
break;
|
||||||
case RET_VOID: memcpy(TypeBuffer, "Void", 4); break;
|
case RET_INT:
|
||||||
default: break;
|
memcpy(TypeBuffer, "Int ", 4);
|
||||||
|
break;
|
||||||
|
case RET_LONG:
|
||||||
|
memcpy(TypeBuffer, "Long", 4);
|
||||||
|
break;
|
||||||
|
case RET_VOID:
|
||||||
|
memcpy(TypeBuffer, "Void", 4);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
};
|
};
|
||||||
if(TypeIsPtr(Type)) memcpy((void*)((size_t) TypeBuffer + 4), "Ptr", 3);
|
if (TypeIsPtr(Type)) memcpy((void*) ((size_t) TypeBuffer + 4), "Ptr", 3);
|
||||||
else memcpy((void*)((size_t) TypeBuffer + 4), " ", 3);
|
else memcpy((void*) ((size_t) TypeBuffer + 4), " ", 3);
|
||||||
return TypeBuffer;
|
return TypeBuffer;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -104,7 +116,7 @@ int TypesCompatible(int* Left, int* Right, int STRICT) {
|
||||||
int LeftSize, RightSize;
|
int LeftSize, RightSize;
|
||||||
|
|
||||||
// Same types are compatible. No shrinking required
|
// Same types are compatible. No shrinking required
|
||||||
if(*Left == *Right) {
|
if (*Left == *Right) {
|
||||||
*Left = *Right = 0;
|
*Left = *Right = 0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -114,7 +126,7 @@ int TypesCompatible(int* Left, int* Right, int STRICT) {
|
||||||
|
|
||||||
|
|
||||||
// Types of size 0 are incompatible
|
// Types of size 0 are incompatible
|
||||||
if((LeftSize == 0) || (RightSize == 0))
|
if ((LeftSize == 0) || (RightSize == 0))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|
||||||
|
@ -126,7 +138,7 @@ int TypesCompatible(int* Left, int* Right, int STRICT) {
|
||||||
* x needs to be widened, y copied in, then x shrunk back down
|
* x needs to be widened, y copied in, then x shrunk back down
|
||||||
* AKA, the left must be widened.
|
* AKA, the left must be widened.
|
||||||
*/
|
*/
|
||||||
if(LeftSize < RightSize) {
|
if (LeftSize < RightSize) {
|
||||||
*Left = OP_WIDEN;
|
*Left = OP_WIDEN;
|
||||||
*Right = 0;
|
*Right = 0;
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -145,10 +157,10 @@ int TypesCompatible(int* Left, int* Right, int STRICT) {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if(LeftSize > RightSize) {
|
if (LeftSize > RightSize) {
|
||||||
if(STRICT)
|
if (STRICT)
|
||||||
return 0; // Not compatible if STRICT
|
return 0; // Not compatible if STRICT
|
||||||
|
|
||||||
*Left = 0;
|
*Left = 0;
|
||||||
*Right = OP_WIDEN;
|
*Right = OP_WIDEN;
|
||||||
return 1; // Compatible by default
|
return 1; // Compatible by default
|
||||||
|
@ -191,10 +203,10 @@ struct ASTNode* MutateType(struct ASTNode* Tree, int RightType, int Operation) {
|
||||||
|
|
||||||
|
|
||||||
printf("\tCalculating compatibility between ltype %d and rtype %d\r\n", LeftType, RightType);
|
printf("\tCalculating compatibility between ltype %d and rtype %d\r\n", LeftType, RightType);
|
||||||
if(TypeIsInt(LeftType) && TypeIsInt(RightType)) {
|
if (TypeIsInt(LeftType) && TypeIsInt(RightType)) {
|
||||||
|
|
||||||
// Short-circuit for valid types
|
// Short-circuit for valid types
|
||||||
if(LeftType == RightType) {
|
if (LeftType == RightType) {
|
||||||
return Tree;
|
return Tree;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,7 +220,7 @@ struct ASTNode* MutateType(struct ASTNode* Tree, int RightType, int Operation) {
|
||||||
* (The left branch of the tree contains the current AST)
|
* (The left branch of the tree contains the current AST)
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
if(LeftSize > RightSize)
|
if (LeftSize > RightSize)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -220,19 +232,19 @@ struct ASTNode* MutateType(struct ASTNode* Tree, int RightType, int Operation) {
|
||||||
* BUT it is possible!
|
* BUT it is possible!
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if(RightSize > LeftSize)
|
if (RightSize > LeftSize)
|
||||||
return ConstructASTBranch(OP_WIDEN, RightType, Tree, NULL, 0);
|
return ConstructASTBranch(OP_WIDEN, RightType, Tree, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Left branch pointers are compatible if we're not doing operations
|
// Left branch pointers are compatible if we're not doing operations
|
||||||
if(TypeIsPtr(LeftType)) {
|
if (TypeIsPtr(LeftType)) {
|
||||||
if(Operation == 0 && LeftType == RightType)
|
if (Operation == 0 && LeftType == RightType)
|
||||||
return Tree;
|
return Tree;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Otherwise, we can perform some scaling for pointer addition & subtraction
|
// Otherwise, we can perform some scaling for pointer addition & subtraction
|
||||||
if(Operation == OP_ADD || Operation == OP_SUBTRACT) {
|
if (Operation == OP_ADD || Operation == OP_SUBTRACT) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Left int, right pointer:
|
* Left int, right pointer:
|
||||||
|
@ -242,11 +254,11 @@ struct ASTNode* MutateType(struct ASTNode* Tree, int RightType, int Operation) {
|
||||||
* x = *(y + 1);
|
* x = *(y + 1);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if(TypeIsInt(LeftType) && TypeIsPtr(RightType)) {
|
if (TypeIsInt(LeftType) && TypeIsPtr(RightType)) {
|
||||||
printf("\t\t\tMutateType: Right node needs adjustment\r\n");
|
printf("\t\t\tMutateType: Right node needs adjustment\r\n");
|
||||||
RightSize = PrimitiveSize(ValueAt(RightType));
|
RightSize = PrimitiveSize(ValueAt(RightType));
|
||||||
|
|
||||||
if(RightSize > 1)
|
if (RightSize > 1)
|
||||||
return ConstructASTBranch(OP_SCALE, RightType, Tree, NULL, RightSize);
|
return ConstructASTBranch(OP_SCALE, RightType, Tree, NULL, RightSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
6
tests/calls.c
Normal file
6
tests/calls.c
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
printf("%d\n", 55);
|
||||||
|
puts("more sup\n");
|
||||||
|
}
|
|
@ -6,8 +6,8 @@ int :: close(int fd);
|
||||||
char* textbuffer;
|
char* textbuffer;
|
||||||
|
|
||||||
int :: main() {
|
int :: main() {
|
||||||
int sourcefile;
|
long sourcefile;
|
||||||
int count;
|
long count;
|
||||||
|
|
||||||
textbuffer = " ";
|
textbuffer = " ";
|
||||||
|
|
||||||
|
|
|
@ -3,11 +3,11 @@ struct a {
|
||||||
int y
|
int y
|
||||||
};
|
};
|
||||||
|
|
||||||
int printf(char* fmt);
|
int :: printf(char* fmt);
|
||||||
|
|
||||||
struct a str;
|
struct a str;
|
||||||
|
|
||||||
int main() {
|
int :: main() {
|
||||||
str.y = 55;
|
str.y = 55;
|
||||||
printf("%d\n", str.y);
|
printf("%d\n", str.y);
|
||||||
return (0);
|
return (0);
|
||||||
|
|
23
tests/structbrutal.er
Normal file
23
tests/structbrutal.er
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
int :: printf(char* fmt);
|
||||||
|
|
||||||
|
struct banana {
|
||||||
|
int x,
|
||||||
|
int y
|
||||||
|
};
|
||||||
|
|
||||||
|
struct banana bread;
|
||||||
|
struct banana* loaf;
|
||||||
|
|
||||||
|
int :: main() {
|
||||||
|
bread.y = 5;
|
||||||
|
loaf->y = 10;
|
||||||
|
|
||||||
|
printf("%d\n", bread.y);
|
||||||
|
printf("%d\n", loaf->y);
|
||||||
|
|
||||||
|
bread.x = 7;
|
||||||
|
|
||||||
|
printf("%d\n", bread.y + bread.x);
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user