Begin refactor for multiplexed compilation
This commit is contained in:
parent
f2d2d07709
commit
37cdaacc71
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -1,6 +1,10 @@
|
||||||
.idea
|
.idea
|
||||||
.vscode
|
.vscode
|
||||||
|
.cache
|
||||||
|
|
||||||
out
|
out
|
||||||
bin
|
bin
|
||||||
|
|
||||||
|
build
|
||||||
|
Erythro
|
||||||
|
test
|
|
@ -17,4 +17,5 @@ add_executable(Erythro
|
||||||
src/Pointers.c
|
src/Pointers.c
|
||||||
src/Statements.c
|
src/Statements.c
|
||||||
src/Symbols.c
|
src/Symbols.c
|
||||||
src/Types.c)
|
src/Types.c
|
||||||
|
src/Importer.c)
|
||||||
|
|
|
@ -16,42 +16,48 @@
|
||||||
#define TEXTLEN 512
|
#define TEXTLEN 512
|
||||||
#define SYMBOLS 1024
|
#define SYMBOLS 1024
|
||||||
|
|
||||||
|
// All currently open source files.
|
||||||
|
extern_ struct FileData** Files;
|
||||||
|
// The source file currently being operated on.
|
||||||
|
extern_ struct FileData* CurrentFile;
|
||||||
|
// The file we are writing into; CurrentFile -> OutputFile
|
||||||
|
extern_ FILE* OutputFile;
|
||||||
|
|
||||||
|
// Symbol tables.
|
||||||
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* CompositeMembers, * CompositeMembersEnd;
|
extern_ struct SymbolTableEntry* CompositeMembers, * CompositeMembersEnd;
|
||||||
extern_ struct SymbolTableEntry* EnumMembers, * EnumMembersEnd;
|
extern_ struct SymbolTableEntry* EnumMembers, * EnumMembersEnd;
|
||||||
|
|
||||||
extern_ struct SymbolTableEntry* Unions, * UnionsEnd;
|
extern_ struct SymbolTableEntry* Unions, * UnionsEnd;
|
||||||
extern_ struct SymbolTableEntry* Enums, * EnumsEnd;
|
extern_ struct SymbolTableEntry* Enums, * EnumsEnd;
|
||||||
extern_ struct SymbolTableEntry* Types, * TypesEnd;
|
extern_ struct SymbolTableEntry* Types, * TypesEnd;
|
||||||
|
|
||||||
|
// Whether we should dump the syntax tree before starting to assemble the file.
|
||||||
extern_ bool OptDumpTree;
|
extern_ bool OptDumpTree;
|
||||||
|
// Whether we should keep the assembly files after successfully linking.
|
||||||
extern_ bool OptKeepAssembly;
|
extern_ bool OptKeepAssembly;
|
||||||
|
// Whether to stop at compilation and dumping - skip assembly and binary creation altogether.
|
||||||
extern_ bool OptAssembleFiles;
|
extern_ bool OptAssembleFiles;
|
||||||
|
// Whether to stop at assembly - skip linking into a binary.
|
||||||
extern_ bool OptLinkFiles;
|
extern_ bool OptLinkFiles;
|
||||||
|
// Whether to output extended debugging information.
|
||||||
extern_ bool OptVerboseOutput;
|
extern_ bool OptVerboseOutput;
|
||||||
|
|
||||||
|
// The name of the binary we want to create.
|
||||||
extern_ char* OutputFileName;
|
extern_ char* OutputFileName;
|
||||||
extern_ char* CurrentASMFile, * CurrentObjectFile;
|
// The sizes of each of the core types, in bytes.
|
||||||
|
|
||||||
extern_ int TypeSizes[5];
|
extern_ int TypeSizes[5];
|
||||||
|
|
||||||
|
// The names of each token in the language, synchronized to the TokenTypes enum.
|
||||||
extern_ char* TokenNames[];
|
extern_ char* TokenNames[];
|
||||||
|
|
||||||
|
// The names of the storage scopes.
|
||||||
extern_ char* ScopeNames[];
|
extern_ char* ScopeNames[];
|
||||||
|
|
||||||
extern_ int CurrentFunction;
|
|
||||||
extern_ struct SymbolTableEntry* FunctionEntry;
|
|
||||||
extern_ int Line;
|
|
||||||
extern_ int Overread;
|
extern_ int Overread;
|
||||||
|
|
||||||
extern_ FILE* SourceFile;
|
|
||||||
extern_ FILE* OutputFile;
|
|
||||||
|
|
||||||
extern_ struct Token CurrentToken;
|
|
||||||
extern_ char CurrentIdentifier[TEXTLEN + 1];
|
extern_ char CurrentIdentifier[TEXTLEN + 1];
|
||||||
|
|
||||||
extern_ int CurrentGlobal;
|
extern_ int CurrentGlobal;
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ARithmetic tokens are prefixed AR.
|
* ARithmetic tokens are prefixed AR.
|
||||||
* LIteral tokens are prefixed LI.
|
* LIteral tokens are prefixed LI.
|
||||||
|
@ -99,7 +100,9 @@ enum TokenTypes {
|
||||||
KW_STRUCT,
|
KW_STRUCT,
|
||||||
KW_UNION,
|
KW_UNION,
|
||||||
KW_ENUM,
|
KW_ENUM,
|
||||||
KW_ALIAS
|
KW_ALIAS,
|
||||||
|
|
||||||
|
KW_IMPORT
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -113,6 +116,9 @@ enum TokenTypes {
|
||||||
*
|
*
|
||||||
* It is important that Tokens and Operations are logically separated,
|
* It is important that Tokens and Operations are logically separated,
|
||||||
* but that the Operation's index is the same as the Token that invokes it.
|
* but that the Operation's index is the same as the Token that invokes it.
|
||||||
|
*
|
||||||
|
* Every five elements, an index is assigned. These are the natural indices.
|
||||||
|
* They are marked to make navigation of the Syntax Tree easier.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
enum SyntaxOps {
|
enum SyntaxOps {
|
||||||
|
@ -173,7 +179,17 @@ enum SyntaxOps {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// A node in a Binary Tree that forms the syntax of Erythro
|
/**
|
||||||
|
* The way syntax is stored by the parser and assembled into a usable file.
|
||||||
|
* An ASTNode forms an item in a linked list.
|
||||||
|
*
|
||||||
|
* Thus, you can traverse up and down a tree of ASTNodes easily.
|
||||||
|
*
|
||||||
|
* Walking the tree is as simple as reading the Operation and recursively reading the Left, Middle and Right nodes as called for.
|
||||||
|
* For example, an if-else statement uses all three subnodes.
|
||||||
|
*
|
||||||
|
* This means that AST Nodes aren't exactly a binary tree, but a syntax tree nonetheless.
|
||||||
|
*/
|
||||||
struct ASTNode {
|
struct ASTNode {
|
||||||
int Operation; // SyntaxOps Index
|
int Operation; // SyntaxOps Index
|
||||||
int ExprType; // Value->IntValue's DataType
|
int ExprType; // Value->IntValue's DataType
|
||||||
|
@ -188,6 +204,12 @@ struct ASTNode {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describes the basic unit of syntax in the language.
|
||||||
|
* A token has a type (an index into the TokenTypes enum) and a value.
|
||||||
|
*
|
||||||
|
* The value represents the numerical value of an integer literal, etc.
|
||||||
|
*/
|
||||||
struct Token {
|
struct Token {
|
||||||
int type;
|
int type;
|
||||||
int value;
|
int value;
|
||||||
|
@ -219,6 +241,47 @@ struct SymbolTableEntry {
|
||||||
struct SymbolTableEntry* Start; // The first member in a list
|
struct SymbolTableEntry* Start; // The first member in a list
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information about a given source file.
|
||||||
|
*
|
||||||
|
* A file that starts the parsing of another file will never confuse the parser.
|
||||||
|
*
|
||||||
|
* It is the end goal that the parser will be multithreaded, operating on a single file at a time.
|
||||||
|
*
|
||||||
|
* Note that files do not contain their own symbol tables - these are global.
|
||||||
|
*/
|
||||||
|
struct FileData {
|
||||||
|
// Whether or not this file will accept definitions of functions.
|
||||||
|
bool AllowDefinitions;
|
||||||
|
|
||||||
|
// A FILE stream that we can read the file from.
|
||||||
|
FILE* Stream;
|
||||||
|
|
||||||
|
// The filename of the source code
|
||||||
|
char* SourceName;
|
||||||
|
// The filename of the assembly output
|
||||||
|
char* AssemblyName;
|
||||||
|
// The filename of the assembled object code
|
||||||
|
char* ObjectName;
|
||||||
|
|
||||||
|
// The full contents of the source file
|
||||||
|
char* Content;
|
||||||
|
// The line of the file we are currently working on, -1 if it is finished
|
||||||
|
long CurrentLine;
|
||||||
|
// The column of the file we are currently working on, -1 if it is finished
|
||||||
|
long CurrentColumn;
|
||||||
|
|
||||||
|
// The symbol currently being lexed - TokenTypes index and integer value.
|
||||||
|
struct Token CurrentSymbol;
|
||||||
|
// The function currently being parsed - null if in global scope or if finished.
|
||||||
|
struct SymbolTableEntry* FunctionEntry;
|
||||||
|
|
||||||
|
// Once ready, the full AST trees of this file.
|
||||||
|
struct ASTNode* Tree;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
enum StorageScope {
|
enum StorageScope {
|
||||||
SC_GLOBAL = 1, // Global Scope
|
SC_GLOBAL = 1, // Global Scope
|
||||||
SC_STRUCT, // Struct Definitions
|
SC_STRUCT, // Struct Definitions
|
||||||
|
@ -255,6 +318,7 @@ enum DataTypes {
|
||||||
DAT_UNION, // Union Data
|
DAT_UNION, // Union Data
|
||||||
DAT_ENUM, // Enum Data
|
DAT_ENUM, // Enum Data
|
||||||
DAT_ALIAS, // Alias Definition
|
DAT_ALIAS, // Alias Definition
|
||||||
|
DAT_NONE, // No type, no work needed.
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -278,11 +342,11 @@ enum StructureType {
|
||||||
|
|
||||||
char* Suffixate(char* String, char Suffix);
|
char* Suffixate(char* String, char Suffix);
|
||||||
|
|
||||||
char* Compile(char* InputFile);
|
void Compile(struct FileData* InputFile);
|
||||||
|
|
||||||
char* Assemble(char* InputFile);
|
void Assemble(struct FileData* InputFile);
|
||||||
|
|
||||||
void Link(char* Output, char* Objects[]);
|
void Link(char* Output, struct FileData* Objects[]);
|
||||||
|
|
||||||
void DisplayUsage(char* ProgName);
|
void DisplayUsage(char* ProgName);
|
||||||
|
|
||||||
|
@ -291,7 +355,6 @@ void DisplayUsage(char* ProgName);
|
||||||
* * * * * * * * * L E X I N G * * * * * * * * *
|
* * * * * * * * * L E X I N G * * * * * * * * *
|
||||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
|
|
||||||
void Tokenise();
|
void Tokenise();
|
||||||
|
|
||||||
void VerifyToken(int Type, char* TokenExpected);
|
void VerifyToken(int Type, char* TokenExpected);
|
||||||
|
@ -302,6 +365,8 @@ static int ReadIdentifier(int Char, char* Buffer, int Limit);
|
||||||
|
|
||||||
static int ReadKeyword(char* Str);
|
static int ReadKeyword(char* Str);
|
||||||
|
|
||||||
|
void ImportModule();
|
||||||
|
|
||||||
/* * * * * * * * * * * * * * * * * * * *
|
/* * * * * * * * * * * * * * * * * * * *
|
||||||
* * * * * T Y P E S * * * * * *
|
* * * * * T Y P E S * * * * * *
|
||||||
* * * * * * * * * * * * * * * * * * * */
|
* * * * * * * * * * * * * * * * * * * */
|
||||||
|
@ -331,8 +396,7 @@ 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*
|
struct ASTNode* ConstructASTBranch(int Operation, int Type, struct ASTNode* Left, struct SymbolTableEntry* Symbol, int IntValue);
|
||||||
ConstructASTBranch(int Operation, int Type, struct ASTNode* Left, struct SymbolTableEntry* Symbol, int IntValue);
|
|
||||||
|
|
||||||
|
|
||||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
@ -483,7 +547,6 @@ 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);
|
||||||
|
|
|
@ -161,7 +161,7 @@ int AssembleTree(struct ASTNode* Node, int Register, int ParentOp) {
|
||||||
|
|
||||||
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(CurrentFile->FunctionEntry, LeftVal);
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
case OP_EQUAL:
|
case OP_EQUAL:
|
||||||
|
@ -856,13 +856,13 @@ void AsGlobalSymbol(struct SymbolTableEntry* Entry) {
|
||||||
|
|
||||||
switch (Size) {
|
switch (Size) {
|
||||||
case 1:
|
case 1:
|
||||||
fprintf(OutputFile, "\t.byte\t0\r\n", Entry->Name);
|
fprintf(OutputFile, "\t.byte\t0\r\n");
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
fprintf(OutputFile, "\t.long\t0\r\n", Entry->Name);
|
fprintf(OutputFile, "\t.long\t0\r\n");
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
fprintf(OutputFile, "\t.quad\t0\r\n", Entry->Name);
|
fprintf(OutputFile, "\t.quad\t0\r\n");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
for (int i = 0; i < Size; i++)
|
for (int i = 0; i < Size; i++)
|
||||||
|
|
|
@ -62,19 +62,19 @@ char* Suffixate(char* String, char Suffix) {
|
||||||
* For Erythro code, this is .er
|
* For Erythro code, this is .er
|
||||||
* The generated assembly will have the extension .s
|
* The generated assembly will have the extension .s
|
||||||
*
|
*
|
||||||
* @param InputFile: The filename of the Erythro Source code to compile
|
* @param InputFile: A pointer to the data that we should use to compile this file.
|
||||||
* @return the filename of the generated PECOFF32+ assembly
|
* @return the filename of the generated PECOFF32+ assembly
|
||||||
*/
|
*/
|
||||||
char* Compile(char* InputFile) {
|
void Compile(struct FileData* InputFile) {
|
||||||
char* OutputName;
|
char* OutputName;
|
||||||
OutputName = Suffixate(InputFile, 's');
|
OutputName = Suffixate(InputFile->SourceName, '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->SourceName);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((SourceFile = fopen(InputFile, "r")) == NULL) {
|
if ((InputFile->Stream = fopen(InputFile->SourceName, "r")) == NULL) {
|
||||||
fprintf(stderr, "Unable to open %s: %s\n", InputFile, strerror(errno));
|
fprintf(stderr, "Unable to open %s: %s\n", InputFile->SourceName, strerror(errno));
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,13 +83,15 @@ char* Compile(char* InputFile) {
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
Line = 1;
|
InputFile->AssemblyName = OutputName;
|
||||||
|
CurrentFile = InputFile;
|
||||||
|
|
||||||
|
CurrentFile->CurrentLine = 1;
|
||||||
Overread = '\n';
|
Overread = '\n';
|
||||||
CurrentGlobal = 0;
|
|
||||||
CurrentLocal = SYMBOLS - 1;
|
|
||||||
|
|
||||||
if (OptVerboseOutput)
|
if (OptVerboseOutput)
|
||||||
printf("Compiling %s\r\n", InputFile);
|
printf("Compiling %s\r\n", CurrentFile->SourceName);
|
||||||
|
|
||||||
Tokenise();
|
Tokenise();
|
||||||
|
|
||||||
|
@ -97,8 +99,9 @@ char* Compile(char* InputFile) {
|
||||||
|
|
||||||
ParseGlobals();
|
ParseGlobals();
|
||||||
|
|
||||||
|
// Output.Tree = ParseGlobals();
|
||||||
|
|
||||||
fclose(OutputFile);
|
fclose(OutputFile);
|
||||||
return OutputName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -115,27 +118,26 @@ char* Compile(char* InputFile) {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
char* Assemble(char* InputFile) {
|
void Assemble(struct FileData* InputFile) {
|
||||||
char Command[TEXTLEN];
|
char Command[TEXTLEN];
|
||||||
int Error;
|
int Error;
|
||||||
char* OutputName;
|
char* OutputName;
|
||||||
OutputName = Suffixate(InputFile, 'o');
|
OutputName = Suffixate(InputFile->AssemblyName, '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->AssemblyName);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(Command, TEXTLEN, "%s %s %s", "as -o ", OutputName, InputFile);
|
snprintf(Command, TEXTLEN, "%s %s %s", "as -o ", OutputName, InputFile->AssemblyName);
|
||||||
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 error code %d\n", InputFile->AssemblyName, Error);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
return OutputName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -150,7 +152,7 @@ char* Assemble(char* InputFile) {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void Link(char* Output, char* Objects[]) {
|
void Link(char* Output, struct FileData* Objects[]) {
|
||||||
int Count, Size = TEXTLEN, Error;
|
int Count, Size = TEXTLEN, Error;
|
||||||
char Command[TEXTLEN], * CommandPtr;
|
char Command[TEXTLEN], * CommandPtr;
|
||||||
|
|
||||||
|
@ -160,7 +162,7 @@ void Link(char* Output, char* Objects[]) {
|
||||||
Size -= Count;
|
Size -= Count;
|
||||||
|
|
||||||
while (*Objects != NULL) {
|
while (*Objects != NULL) {
|
||||||
Count = snprintf(CommandPtr, Size, "%s ", *Objects);
|
Count = snprintf(CommandPtr, Size, "%s ", (*Objects)->ObjectName);
|
||||||
CommandPtr += Count;
|
CommandPtr += Count;
|
||||||
Size -= Count;
|
Size -= Count;
|
||||||
Objects++;
|
Objects++;
|
||||||
|
|
|
@ -107,10 +107,7 @@ void DumpTree(struct ASTNode* Node, int level) {
|
||||||
fprintf(stdout, "TERM_STRLITERAL rval L%d\n", Node->IntValue);
|
fprintf(stdout, "TERM_STRLITERAL rval L%d\n", Node->IntValue);
|
||||||
return;
|
return;
|
||||||
case REF_IDENT:
|
case REF_IDENT:
|
||||||
if (Node->RVal)
|
fprintf(stdout, "REF_IDENT%s %s\n", Node->RVal ? " rval" : "", Node->Symbol->Name);
|
||||||
fprintf(stdout, "REF_IDENT rval %s\n", Node->Symbol->Name);
|
|
||||||
else
|
|
||||||
fprintf(stdout, "REF_IDENT %s\n", Node->Symbol->Name);
|
|
||||||
return;
|
return;
|
||||||
case OP_ASSIGN:
|
case OP_ASSIGN:
|
||||||
fprintf(stdout, "OP_ASSIGN\n");
|
fprintf(stdout, "OP_ASSIGN\n");
|
||||||
|
|
75
src/Importer.c
Normal file
75
src/Importer.c
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
|
||||||
|
/*************/
|
||||||
|
/*GEMWIRE */
|
||||||
|
/* ERYTHRO*/
|
||||||
|
/*************/
|
||||||
|
|
||||||
|
#include <Defs.h>
|
||||||
|
#include <Data.h>
|
||||||
|
#include <linux/limits.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function of the importer is to read in definitions from a file, and store
|
||||||
|
* them into the symbol tables.
|
||||||
|
*
|
||||||
|
* The file to be imported is called a "module", which is Erythro terminology for C-like "headers".
|
||||||
|
* They contain extra metadata that allows for Erythro's enhanced debugging and error logging.
|
||||||
|
*
|
||||||
|
* Modules may also contain metadata about the contents within - allowing for multiple compile-time
|
||||||
|
* sourcesets with different arguments, all parsed at the same time as the source code.
|
||||||
|
*
|
||||||
|
* This allows Erythro to have first-class support for multiple-build-single-link situations,
|
||||||
|
* that would require the use of a build system like CMake in other languages.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read in the information of a module, check that it is valid, and then read the module itself.
|
||||||
|
* Import syntax looks like:
|
||||||
|
*
|
||||||
|
* > import "file"
|
||||||
|
*
|
||||||
|
* The string is appended to the current working directory and is checked.
|
||||||
|
* If the resulting path exists and resolves to a file, then the file's declarations are added to the symbol tables.
|
||||||
|
*
|
||||||
|
* Modules may not contain definitions. Only declarations
|
||||||
|
* TODO: Module metadata as described above.
|
||||||
|
*/
|
||||||
|
void ImportModule() {
|
||||||
|
// Skip the import keyword
|
||||||
|
Tokenise();
|
||||||
|
|
||||||
|
// Make sure there's a string after the import.
|
||||||
|
if (CurrentFile->CurrentSymbol.type != LI_STR)
|
||||||
|
Die("Import statement must be followed by a compile-time constant string.");
|
||||||
|
|
||||||
|
// Read in the string that we know must be there.
|
||||||
|
char* Module = strdup(CurrentIdentifier);
|
||||||
|
|
||||||
|
// Figure out the working directory
|
||||||
|
char CWD[PATH_MAX];
|
||||||
|
|
||||||
|
if (getcwd(CWD, sizeof(CWD)) == NULL)
|
||||||
|
DieMessage("Unable to find cwd when importing module", Module);
|
||||||
|
|
||||||
|
// Append the module name to the current working directory
|
||||||
|
char* ModulePath = malloc(sizeof(CWD) + sizeof(Module) + 1);
|
||||||
|
strcpy(ModulePath, CWD);
|
||||||
|
strcpy(ModulePath, Module);
|
||||||
|
|
||||||
|
printf("Scanning %s for module definitions.\n", ModulePath);
|
||||||
|
|
||||||
|
// Stat the file to see if it exists
|
||||||
|
struct stat FileInfo;
|
||||||
|
if (stat(ModulePath, &FileInfo) != 0)
|
||||||
|
DieMessage("Unable to access the imported module", ModulePath);
|
||||||
|
|
||||||
|
// At this point, the file exists and we have the path.
|
||||||
|
// Pass it to the lexer and have at it.
|
||||||
|
|
||||||
|
}
|
17
src/Lexer.c
17
src/Lexer.c
|
@ -43,10 +43,10 @@ static int NextChar(void) {
|
||||||
return Char;
|
return Char;
|
||||||
}
|
}
|
||||||
|
|
||||||
Char = fgetc(SourceFile);
|
Char = fgetc(CurrentFile->Stream);
|
||||||
|
|
||||||
if (Char == '\n')
|
if (Char == '\n')
|
||||||
Line++;
|
CurrentFile->CurrentLine++;
|
||||||
|
|
||||||
return Char;
|
return Char;
|
||||||
}
|
}
|
||||||
|
@ -91,10 +91,10 @@ static int FindDigitFromPos(char* String, char Char) {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void VerifyToken(int Type, char* TokenExpected) {
|
void VerifyToken(int Type, char* TokenExpected) {
|
||||||
if (CurrentToken.type == Type)
|
if (CurrentFile->CurrentSymbol.type == Type)
|
||||||
Tokenise();
|
Tokenise();
|
||||||
else {
|
else {
|
||||||
printf("Expected %s on line %d\n", TokenExpected, Line);
|
printf("Expected %s on line %ld\n", TokenExpected, CurrentFile->CurrentLine);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -170,7 +170,7 @@ static int ReadIdentifier(int Char, char* Buffer, int Limit) {
|
||||||
// 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: %ld\n", CurrentFile->CurrentLine);
|
||||||
exit(1);
|
exit(1);
|
||||||
} else {
|
} else {
|
||||||
Buffer[ind++] = Char;
|
Buffer[ind++] = Char;
|
||||||
|
@ -319,6 +319,9 @@ static int ReadKeyword(char* Str) {
|
||||||
if (!strcmp(Str, "int"))
|
if (!strcmp(Str, "int"))
|
||||||
return TY_INT;
|
return TY_INT;
|
||||||
|
|
||||||
|
if (!strcmp(Str, "import"))
|
||||||
|
return KW_IMPORT;
|
||||||
|
|
||||||
if (!strcmp(Str, "if"))
|
if (!strcmp(Str, "if"))
|
||||||
return KW_IF;
|
return KW_IF;
|
||||||
|
|
||||||
|
@ -384,7 +387,7 @@ static int ReadKeyword(char* Str) {
|
||||||
*/
|
*/
|
||||||
void Tokenise() {
|
void Tokenise() {
|
||||||
int Char, TokenType;
|
int Char, TokenType;
|
||||||
struct Token* Token = &CurrentToken;
|
struct Token* Token = &CurrentFile->CurrentSymbol;
|
||||||
|
|
||||||
if (RejectedToken != NULL) {
|
if (RejectedToken != NULL) {
|
||||||
Token = RejectedToken;
|
Token = RejectedToken;
|
||||||
|
@ -580,7 +583,7 @@ void Tokenise() {
|
||||||
Char == '_') { // This is what defines what a variable/function/keyword can START with.
|
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;
|
||||||
}
|
}
|
||||||
|
|
53
src/Main.c
53
src/Main.c
|
@ -4,13 +4,10 @@
|
||||||
/*************/
|
/*************/
|
||||||
|
|
||||||
#include <Defs.h>
|
#include <Defs.h>
|
||||||
|
|
||||||
#define extern_
|
#define extern_
|
||||||
|
|
||||||
#include <Data.h>
|
#include <Data.h>
|
||||||
|
|
||||||
#undef extern_
|
#undef extern_
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
|
||||||
int TypeSizes[5] = {0, 1, 4, 8, 0}; // in BYTES
|
int TypeSizes[5] = {0, 1, 4, 8, 0}; // in BYTES
|
||||||
|
@ -105,7 +102,6 @@ int main(int argc, char* argv[]) {
|
||||||
OptVerboseOutput = false;
|
OptVerboseOutput = false;
|
||||||
|
|
||||||
// Temporary .o storage and counter
|
// Temporary .o storage and counter
|
||||||
char* ObjectFiles[100];
|
|
||||||
int ObjectCount = 0;
|
int ObjectCount = 0;
|
||||||
|
|
||||||
// Parse command line arguments.
|
// Parse command line arguments.
|
||||||
|
@ -134,7 +130,7 @@ int main(int argc, char* argv[]) {
|
||||||
OptLinkFiles = false;
|
OptLinkFiles = false;
|
||||||
break;
|
break;
|
||||||
case 'S': // aSsemble only
|
case 'S': // aSsemble only
|
||||||
OptAssembleFiles = false;
|
OptAssembleFiles = true;
|
||||||
OptKeepAssembly = true;
|
OptKeepAssembly = true;
|
||||||
OptLinkFiles = false;
|
OptLinkFiles = false;
|
||||||
break;
|
break;
|
||||||
|
@ -151,40 +147,45 @@ int main(int argc, char* argv[]) {
|
||||||
if (i >= argc)
|
if (i >= argc)
|
||||||
DisplayUsage(argv[0]);
|
DisplayUsage(argv[0]);
|
||||||
|
|
||||||
|
// Allocate enough files for the full specified source code
|
||||||
|
Files = malloc(sizeof(struct FileData) * i);
|
||||||
|
|
||||||
// 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) {
|
||||||
|
// Prepare the source metadata before we start compiling
|
||||||
|
struct FileData* Source = malloc(sizeof(struct FileData));
|
||||||
|
Files[i] = Source;
|
||||||
|
|
||||||
// Compile the file by invoking the Delegate
|
// Compile the file by invoking the Delegate
|
||||||
CurrentASMFile = Compile(argv[i]);
|
Compile(Source);
|
||||||
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);
|
Assemble(Source);
|
||||||
// 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.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move the ObjectCount forward.
|
|
||||||
ObjectFiles[ObjectCount++] = CurrentObjectFile;
|
|
||||||
// Clear the new, forwarded index
|
|
||||||
ObjectFiles[ObjectCount] = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!OptKeepAssembly)
|
if (!OptKeepAssembly)
|
||||||
// unlink = delete
|
// unlink = delete
|
||||||
unlink(CurrentASMFile);
|
unlink(Source->AssemblyName);
|
||||||
|
|
||||||
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, Files);
|
||||||
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; Files[i] != NULL; i++) {
|
||||||
unlink(ObjectFiles[i]);
|
unlink(Files[i]->AssemblyName);
|
||||||
|
unlink(Files[i]->ObjectName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,7 +199,7 @@ int main(int argc, char* argv[]) {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void Die(char* Error) {
|
void Die(char* Error) {
|
||||||
fprintf(stderr, "%s on line %d\n", Error, Line);
|
fprintf(stderr, "%s on line %ld\n", Error, CurrentFile->CurrentLine);
|
||||||
fclose(OutputFile);
|
fclose(OutputFile);
|
||||||
unlink(OutputFileName);
|
unlink(OutputFileName);
|
||||||
exit(1);
|
exit(1);
|
||||||
|
@ -208,7 +209,7 @@ void Die(char* Error) {
|
||||||
* A variant of Die with an extra String attached.
|
* A variant of Die with an extra String attached.
|
||||||
*/
|
*/
|
||||||
void DieMessage(char* Error, char* Reason) {
|
void DieMessage(char* Error, char* Reason) {
|
||||||
fprintf(stderr, "%s: %s on line %d\n", Error, Reason, Line);
|
fprintf(stderr, "%s: %s on line %ld\n", Error, Reason, CurrentFile->CurrentLine);
|
||||||
fclose(OutputFile);
|
fclose(OutputFile);
|
||||||
unlink(OutputFileName);
|
unlink(OutputFileName);
|
||||||
exit(1);
|
exit(1);
|
||||||
|
@ -218,19 +219,7 @@ void DieMessage(char* Error, char* Reason) {
|
||||||
* A variant of Die with an extra integer attached.
|
* A variant of Die with an extra integer attached.
|
||||||
*/
|
*/
|
||||||
void DieDecimal(char* Error, int Number) {
|
void DieDecimal(char* Error, int Number) {
|
||||||
fprintf(stderr, "%s: %d on line %d\n", Error, Number, Line);
|
fprintf(stderr, "%s: %d on line %ld\n", Error, Number, CurrentFile->CurrentLine);
|
||||||
fclose(OutputFile);
|
|
||||||
unlink(OutputFileName);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A variant of Die that prints the int in binary.
|
|
||||||
*/
|
|
||||||
void DieBinary(char* Error, int Number) {
|
|
||||||
char buf[33];
|
|
||||||
itoa(Number, buf, 2);
|
|
||||||
printf("%s: %s\n", Error, buf);
|
|
||||||
fclose(OutputFile);
|
fclose(OutputFile);
|
||||||
unlink(OutputFileName);
|
unlink(OutputFileName);
|
||||||
exit(1);
|
exit(1);
|
||||||
|
@ -240,7 +229,7 @@ void DieBinary(char* Error, int Number) {
|
||||||
* A variant of Die with an extra character attached.
|
* A variant of Die with an extra character attached.
|
||||||
*/
|
*/
|
||||||
void DieChar(char* Error, int Char) {
|
void DieChar(char* Error, int Char) {
|
||||||
fprintf(stderr, "%s: %c on line %d\n", Error, Char, Line);
|
fprintf(stderr, "%s: %c on line %ld\n", Error, Char, CurrentFile->CurrentLine);
|
||||||
fclose(OutputFile);
|
fclose(OutputFile);
|
||||||
unlink(OutputFileName);
|
unlink(OutputFileName);
|
||||||
exit(1);
|
exit(1);
|
||||||
|
|
38
src/Parser.c
38
src/Parser.c
|
@ -230,13 +230,13 @@ struct ASTNode* ParsePrimary(void) {
|
||||||
struct ASTNode* Node;
|
struct ASTNode* Node;
|
||||||
int ID;
|
int ID;
|
||||||
|
|
||||||
switch (CurrentToken.type) {
|
switch (CurrentFile->CurrentSymbol.type) {
|
||||||
case LI_INT:
|
case LI_INT:
|
||||||
|
|
||||||
if ((CurrentToken.value >= 0) && (CurrentToken.value < 256))
|
if ((CurrentFile->CurrentSymbol.value >= 0) && (CurrentFile->CurrentSymbol.value < 256))
|
||||||
Node = ConstructASTLeaf(TERM_INTLITERAL, RET_CHAR, NULL, CurrentToken.value);
|
Node = ConstructASTLeaf(TERM_INTLITERAL, RET_CHAR, NULL, CurrentFile->CurrentSymbol.value);
|
||||||
else
|
else
|
||||||
Node = ConstructASTLeaf(TERM_INTLITERAL, RET_INT, NULL, CurrentToken.value);
|
Node = ConstructASTLeaf(TERM_INTLITERAL, RET_INT, NULL, CurrentFile->CurrentSymbol.value);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LI_STR:
|
case LI_STR:
|
||||||
|
@ -288,7 +288,7 @@ struct ASTNode* ParsePrecedenceASTNode(int PreviousTokenPrecedence) {
|
||||||
|
|
||||||
LeftNode = PrefixStatement();
|
LeftNode = PrefixStatement();
|
||||||
|
|
||||||
NodeType = CurrentToken.type;
|
NodeType = CurrentFile->CurrentSymbol.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;
|
LeftNode->RVal = 1;
|
||||||
|
@ -298,7 +298,7 @@ struct ASTNode* ParsePrecedenceASTNode(int PreviousTokenPrecedence) {
|
||||||
while ((OperatorPrecedence(NodeType) > PreviousTokenPrecedence) ||
|
while ((OperatorPrecedence(NodeType) > PreviousTokenPrecedence) ||
|
||||||
(IsRightExpr(OpType) && OperatorPrecedence(OpType) == PreviousTokenPrecedence)) {
|
(IsRightExpr(OpType) && OperatorPrecedence(OpType) == PreviousTokenPrecedence)) {
|
||||||
Tokenise();
|
Tokenise();
|
||||||
if (CurrentToken.type == LI_RPARE)
|
if (CurrentFile->CurrentSymbol.type == LI_RPARE)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
RightNode = ParsePrecedenceASTNode(Precedence[NodeType]);
|
RightNode = ParsePrecedenceASTNode(Precedence[NodeType]);
|
||||||
|
@ -331,7 +331,7 @@ struct ASTNode* ParsePrecedenceASTNode(int PreviousTokenPrecedence) {
|
||||||
RightTemp = NULL;
|
RightTemp = NULL;
|
||||||
LeftTemp = NULL;
|
LeftTemp = NULL;
|
||||||
} else {
|
} else {
|
||||||
printf("\t\tAttempting to handle a %d in Binary Expression parsing\r\n", CurrentToken.type);
|
printf("\t\tAttempting to handle a %d in Binary Expression parsing\r\n", CurrentFile->CurrentSymbol.type);
|
||||||
LeftNode->RVal = 1;
|
LeftNode->RVal = 1;
|
||||||
RightNode->RVal = 1;
|
RightNode->RVal = 1;
|
||||||
|
|
||||||
|
@ -370,7 +370,7 @@ struct ASTNode* ParsePrecedenceASTNode(int PreviousTokenPrecedence) {
|
||||||
|
|
||||||
LeftNode = ConstructASTNode(ParseTokenToOperation(NodeType), LeftNode->ExprType, LeftNode, NULL, RightNode,
|
LeftNode = ConstructASTNode(ParseTokenToOperation(NodeType), LeftNode->ExprType, LeftNode, NULL, RightNode,
|
||||||
NULL, 0);
|
NULL, 0);
|
||||||
NodeType = CurrentToken.type;
|
NodeType = CurrentFile->CurrentSymbol.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;
|
||||||
|
@ -435,13 +435,13 @@ 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 (CurrentFile->CurrentSymbol.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 (CurrentFile->CurrentSymbol.type) {
|
||||||
case LI_COM:
|
case LI_COM:
|
||||||
Tokenise();
|
Tokenise();
|
||||||
break;
|
break;
|
||||||
|
@ -475,8 +475,8 @@ 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[CurrentFile->CurrentSymbol.type], CurrentFile->CurrentSymbol.type);
|
||||||
switch (CurrentToken.type) {
|
switch (CurrentFile->CurrentSymbol.type) {
|
||||||
case TY_CHAR:
|
case TY_CHAR:
|
||||||
case TY_LONG:
|
case TY_LONG:
|
||||||
case TY_INT:
|
case TY_INT:
|
||||||
|
@ -544,7 +544,7 @@ struct ASTNode* ParseCompound() {
|
||||||
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 (CurrentFile->CurrentSymbol.type == LI_RBRAC) {
|
||||||
VerifyToken(LI_RBRAC, "}");
|
VerifyToken(LI_RBRAC, "}");
|
||||||
return Left;
|
return Left;
|
||||||
}
|
}
|
||||||
|
@ -577,28 +577,32 @@ void ParseGlobals() {
|
||||||
|
|
||||||
// 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 (CurrentFile->CurrentSymbol.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 (CurrentFile->CurrentSymbol.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 || Type == DAT_UNION || Type == DAT_ENUM || Type == DAT_ALIAS) && CurrentToken.type == LI_SEMIC) {
|
if ((Type == DAT_STRUCT || Type == DAT_UNION || Type == DAT_ENUM || Type == DAT_ALIAS) && CurrentFile->CurrentSymbol.type == LI_SEMIC) {
|
||||||
Tokenise();
|
Tokenise();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we read metadata or an import, then skip all processing.
|
||||||
|
if (Type == DAT_NONE)
|
||||||
|
continue;
|
||||||
|
|
||||||
VerifyToken(TY_IDENTIFIER, "ident");
|
VerifyToken(TY_IDENTIFIER, "ident");
|
||||||
|
|
||||||
if (FunctionComing && CurrentToken.type == LI_LPARE) {
|
if (FunctionComing && CurrentFile->CurrentSymbol.type == LI_LPARE) {
|
||||||
printf("\tParsing function\n");
|
printf("\tParsing function\n");
|
||||||
Tree = ParseFunction(Type);
|
Tree = ParseFunction(Type);
|
||||||
if (Tree) {
|
if (Tree) {
|
||||||
|
|
|
@ -75,7 +75,10 @@ int ParseOptionalPointer(struct SymbolTableEntry** Composite) {
|
||||||
|
|
||||||
int Type;
|
int Type;
|
||||||
|
|
||||||
switch (CurrentToken.type) {
|
switch (CurrentFile->CurrentSymbol.type) {
|
||||||
|
case KW_IMPORT:
|
||||||
|
ImportModule();
|
||||||
|
break;
|
||||||
case TY_VOID:
|
case TY_VOID:
|
||||||
Type = RET_VOID;
|
Type = RET_VOID;
|
||||||
Tokenise();
|
Tokenise();
|
||||||
|
@ -97,13 +100,13 @@ int ParseOptionalPointer(struct SymbolTableEntry** Composite) {
|
||||||
break;
|
break;
|
||||||
case KW_ALIAS:
|
case KW_ALIAS:
|
||||||
Type = ReadAlias(Composite);
|
Type = ReadAlias(Composite);
|
||||||
if (CurrentToken.type == LI_SEMIC)
|
if (CurrentFile->CurrentSymbol.type == LI_SEMIC)
|
||||||
Type = DAT_ALIAS;
|
Type = DAT_ALIAS;
|
||||||
break;
|
break;
|
||||||
case KW_ENUM:
|
case KW_ENUM:
|
||||||
Type = RET_INT;
|
Type = RET_INT;
|
||||||
BeginEnumDeclaration();
|
BeginEnumDeclaration();
|
||||||
if (CurrentToken.type == LI_SEMIC)
|
if (CurrentFile->CurrentSymbol.type == LI_SEMIC)
|
||||||
Type = DAT_ENUM;
|
Type = DAT_ENUM;
|
||||||
break;
|
break;
|
||||||
case KW_STRUCT:
|
case KW_STRUCT:
|
||||||
|
@ -115,15 +118,19 @@ int ParseOptionalPointer(struct SymbolTableEntry** Composite) {
|
||||||
*Composite = BeginCompositeDeclaration(Type);
|
*Composite = BeginCompositeDeclaration(Type);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
DieDecimal("Illegal type for pointerisation", CurrentToken.type);
|
DieDecimal("Illegal type for pointerisation", CurrentFile->CurrentSymbol.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);
|
// But, skip parsing if we're looking at an import.
|
||||||
if (CurrentToken.type != AR_STAR)
|
if (CurrentFile->CurrentSymbol.type == KW_IMPORT)
|
||||||
|
break;
|
||||||
|
|
||||||
|
printf("\t\t\tType on parsing is %d\n", CurrentFile->CurrentSymbol.type);
|
||||||
|
if (CurrentFile->CurrentSymbol.type != AR_STAR)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
Type = PointerTo(Type);
|
Type = PointerTo(Type);
|
||||||
|
@ -164,7 +171,7 @@ struct ASTNode* AccessArray() {
|
||||||
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),
|
printf("\t\tPreparing types - RightNode of type %s must be mutated to LeftNode type %s\r\n", TypeNames(RightNode->ExprType),
|
||||||
TypeNames(LeftNode->ExprType));
|
TypeNames(LeftNode->ExprType));
|
||||||
RightNode = MutateType(RightNode, LeftNode->ExprType, OP_ADD);
|
RightNode = MutateType(RightNode, LeftNode->ExprType, OP_ADD);
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ static int ReadDeclarationList(struct SymbolTableEntry* FunctionSymbol, int Stor
|
||||||
if (FunctionSymbol != NULL)
|
if (FunctionSymbol != NULL)
|
||||||
PrototypePointer = FunctionSymbol->Start;
|
PrototypePointer = FunctionSymbol->Start;
|
||||||
|
|
||||||
while (CurrentToken.type != End) {
|
while (CurrentFile->CurrentSymbol.type != End) {
|
||||||
TokenType = ParseOptionalPointer(&Composite);
|
TokenType = ParseOptionalPointer(&Composite);
|
||||||
VerifyToken(TY_IDENTIFIER, "identifier");
|
VerifyToken(TY_IDENTIFIER, "identifier");
|
||||||
|
|
||||||
|
@ -48,10 +48,10 @@ static int ReadDeclarationList(struct SymbolTableEntry* FunctionSymbol, int Stor
|
||||||
}
|
}
|
||||||
ParamCount++;
|
ParamCount++;
|
||||||
|
|
||||||
if ((CurrentToken.type != LI_COM) && (CurrentToken.type != End))
|
if ((CurrentFile->CurrentSymbol.type != LI_COM) && (CurrentFile->CurrentSymbol.type != End))
|
||||||
DieDecimal("Unexpected token in parameter", CurrentToken.type);
|
DieDecimal("Unexpected token in parameter", CurrentFile->CurrentSymbol.type);
|
||||||
|
|
||||||
if (CurrentToken.type == LI_COM)
|
if (CurrentFile->CurrentSymbol.type == LI_COM)
|
||||||
Tokenise();
|
Tokenise();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,12 +80,12 @@ struct SymbolTableEntry* BeginCompositeDeclaration(int Type) {
|
||||||
|
|
||||||
Tokenise();
|
Tokenise();
|
||||||
|
|
||||||
if (CurrentToken.type == TY_IDENTIFIER) {
|
if (CurrentFile->CurrentSymbol.type == TY_IDENTIFIER) {
|
||||||
Composite = Type == DAT_STRUCT ? FindStruct(CurrentIdentifier) : FindUnion(CurrentIdentifier);
|
Composite = Type == DAT_STRUCT ? FindStruct(CurrentIdentifier) : FindUnion(CurrentIdentifier);
|
||||||
Tokenise();
|
Tokenise();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CurrentToken.type != LI_LBRAC) {
|
if (CurrentFile->CurrentSymbol.type != LI_LBRAC) {
|
||||||
if (Composite == NULL)
|
if (Composite == NULL)
|
||||||
DieMessage("Unknown Struct", CurrentIdentifier);
|
DieMessage("Unknown Struct", CurrentIdentifier);
|
||||||
return Composite;
|
return Composite;
|
||||||
|
@ -131,14 +131,14 @@ void BeginEnumDeclaration() {
|
||||||
Tokenise();
|
Tokenise();
|
||||||
|
|
||||||
// enum name
|
// enum name
|
||||||
if (CurrentToken.type == TY_IDENTIFIER) {
|
if (CurrentFile->CurrentSymbol.type == TY_IDENTIFIER) {
|
||||||
Type = FindEnum(CurrentIdentifier);
|
Type = FindEnum(CurrentIdentifier);
|
||||||
Name = strdup(CurrentIdentifier);
|
Name = strdup(CurrentIdentifier);
|
||||||
Tokenise();
|
Tokenise();
|
||||||
}
|
}
|
||||||
|
|
||||||
// enum name {? if not, enum name var.
|
// enum name {? if not, enum name var.
|
||||||
if (CurrentToken.type != LI_LBRAC) {
|
if (CurrentFile->CurrentSymbol.type != LI_LBRAC) {
|
||||||
if (Type == NULL)
|
if (Type == NULL)
|
||||||
DieMessage("Undeclared Enum", Name);
|
DieMessage("Undeclared Enum", Name);
|
||||||
|
|
||||||
|
@ -162,19 +162,19 @@ void BeginEnumDeclaration() {
|
||||||
DieMessage("Attempting to redeclare enum value", Name);
|
DieMessage("Attempting to redeclare enum value", Name);
|
||||||
|
|
||||||
// Parse equality
|
// Parse equality
|
||||||
if (CurrentToken.type == LI_EQUAL) {
|
if (CurrentFile->CurrentSymbol.type == LI_EQUAL) {
|
||||||
Tokenise();
|
Tokenise();
|
||||||
// Expect a number after the equals
|
// Expect a number after the equals
|
||||||
if (CurrentToken.type != LI_INT)
|
if (CurrentFile->CurrentSymbol.type != LI_INT)
|
||||||
Die("Expected integer to assign enum value to");
|
Die("Expected integer to assign enum value to");
|
||||||
Value = CurrentToken.value;
|
Value = CurrentFile->CurrentSymbol.value;
|
||||||
Tokenise();
|
Tokenise();
|
||||||
}
|
}
|
||||||
|
|
||||||
Type = AddSymbol(Name, DAT_ENUM, ST_ENUM, SC_ENUMENTRY, Value++, 0, NULL);
|
Type = AddSymbol(Name, DAT_ENUM, ST_ENUM, SC_ENUMENTRY, Value++, 0, NULL);
|
||||||
|
|
||||||
// Break on right brace
|
// Break on right brace
|
||||||
if (CurrentToken.type == LI_RBRAC)
|
if (CurrentFile->CurrentSymbol.type == LI_RBRAC)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
VerifyToken(LI_COM, "Comma");
|
VerifyToken(LI_COM, "Comma");
|
||||||
|
@ -214,10 +214,10 @@ struct SymbolTableEntry* BeginVariableDeclaration(int Type, struct SymbolTableEn
|
||||||
DieMessage("Invalid redeclaration of Enum/Struct member", CurrentIdentifier);
|
DieMessage("Invalid redeclaration of Enum/Struct member", CurrentIdentifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CurrentToken.type == LI_LBRAS) {
|
if (CurrentFile->CurrentSymbol.type == LI_LBRAS) {
|
||||||
Tokenise();
|
Tokenise();
|
||||||
|
|
||||||
if (CurrentToken.type == LI_INT) {
|
if (CurrentFile->CurrentSymbol.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);
|
||||||
|
@ -284,12 +284,12 @@ struct ASTNode* ParseFunction(int Type) {
|
||||||
|
|
||||||
Params = ParamsEnd = NULL;
|
Params = ParamsEnd = NULL;
|
||||||
|
|
||||||
if (CurrentToken.type == LI_SEMIC) {
|
if (CurrentFile->CurrentSymbol.type == LI_SEMIC) {
|
||||||
Tokenise();
|
Tokenise();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
FunctionEntry = OldFunction;
|
CurrentFile->FunctionEntry = OldFunction;
|
||||||
|
|
||||||
Tree = ParseCompound();
|
Tree = ParseCompound();
|
||||||
|
|
||||||
|
@ -318,7 +318,7 @@ struct ASTNode* ReturnStatement() {
|
||||||
int ReturnType;
|
int ReturnType;
|
||||||
|
|
||||||
|
|
||||||
if (FunctionEntry->Type == RET_VOID)
|
if (CurrentFile->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");
|
||||||
|
@ -327,14 +327,14 @@ struct ASTNode* ReturnStatement() {
|
||||||
|
|
||||||
Tree = ParsePrecedenceASTNode(0);
|
Tree = ParsePrecedenceASTNode(0);
|
||||||
|
|
||||||
Tree = MutateType(Tree, FunctionEntry->Type, 0);
|
Tree = MutateType(Tree, CurrentFile->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, CurrentFile->FunctionEntry, 0);
|
||||||
|
|
||||||
printf("\t\tReturning from function %s\n", FunctionEntry->Name);
|
printf("\t\tReturning from function %s\n", CurrentFile->FunctionEntry->Name);
|
||||||
|
|
||||||
VerifyToken(LI_RPARE, ")"); // TODO: OPTIONALISE!
|
VerifyToken(LI_RPARE, ")"); // TODO: OPTIONALISE!
|
||||||
|
|
||||||
|
@ -385,7 +385,7 @@ struct ASTNode* IfStatement() {
|
||||||
|
|
||||||
True = ParseCompound();
|
True = ParseCompound();
|
||||||
|
|
||||||
if (CurrentToken.type == KW_ELSE) {
|
if (CurrentFile->CurrentSymbol.type == KW_ELSE) {
|
||||||
Tokenise();
|
Tokenise();
|
||||||
False = ParseCompound();
|
False = ParseCompound();
|
||||||
}
|
}
|
||||||
|
@ -573,10 +573,10 @@ struct ASTNode* PostfixStatement() {
|
||||||
|
|
||||||
Tokenise();
|
Tokenise();
|
||||||
|
|
||||||
if (CurrentToken.type == LI_LPARE)
|
if (CurrentFile->CurrentSymbol.type == LI_LPARE)
|
||||||
return CallFunction();
|
return CallFunction();
|
||||||
|
|
||||||
if (CurrentToken.type == LI_LBRAS)
|
if (CurrentFile->CurrentSymbol.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.
|
||||||
|
@ -591,7 +591,7 @@ struct ASTNode* PostfixStatement() {
|
||||||
|
|
||||||
// Here we check for postincrement and postdecrement.
|
// Here we check for postincrement and postdecrement.
|
||||||
|
|
||||||
switch (CurrentToken.type) {
|
switch (CurrentFile->CurrentSymbol.type) {
|
||||||
case LI_DOT:
|
case LI_DOT:
|
||||||
return AccessMember(false);
|
return AccessMember(false);
|
||||||
case LI_ARROW:
|
case LI_ARROW:
|
||||||
|
@ -640,7 +640,7 @@ struct ASTNode* PostfixStatement() {
|
||||||
struct ASTNode* PrefixStatement() {
|
struct ASTNode* PrefixStatement() {
|
||||||
struct ASTNode* Tree;
|
struct ASTNode* Tree;
|
||||||
|
|
||||||
switch (CurrentToken.type) {
|
switch (CurrentFile->CurrentSymbol.type) {
|
||||||
case BOOL_INVERT:
|
case BOOL_INVERT:
|
||||||
Tokenise();
|
Tokenise();
|
||||||
Tree = PrefixStatement();
|
Tree = PrefixStatement();
|
||||||
|
|
|
@ -17,8 +17,8 @@ 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 (CurrentFile->FunctionEntry != NULL && CurrentFile->FunctionEntry->Start != NULL)
|
||||||
DumpList(FunctionEntry->Start);
|
DumpList(CurrentFile->FunctionEntry->Start);
|
||||||
DumpList(Params);
|
DumpList(Params);
|
||||||
printf("\nStructs:\n");
|
printf("\nStructs:\n");
|
||||||
DumpList(Structs);
|
DumpList(Structs);
|
||||||
|
@ -67,8 +67,8 @@ 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 (CurrentFile->FunctionEntry) {
|
||||||
Node = SearchList(Symbol, FunctionEntry->Start);
|
Node = SearchList(Symbol, CurrentFile->FunctionEntry->Start);
|
||||||
if (Node)
|
if (Node)
|
||||||
return Node;
|
return Node;
|
||||||
}
|
}
|
||||||
|
@ -90,8 +90,8 @@ struct SymbolTableEntry* FindSymbol(char* Symbol) {
|
||||||
struct SymbolTableEntry* FindLocal(char* Symbol) {
|
struct SymbolTableEntry* FindLocal(char* Symbol) {
|
||||||
struct SymbolTableEntry* Node;
|
struct SymbolTableEntry* Node;
|
||||||
|
|
||||||
if (FunctionEntry) {
|
if (CurrentFile->FunctionEntry) {
|
||||||
Node = SearchList(Symbol, FunctionEntry->Start);
|
Node = SearchList(Symbol, CurrentFile->FunctionEntry->Start);
|
||||||
if (Node)
|
if (Node)
|
||||||
return Node;
|
return Node;
|
||||||
}
|
}
|
||||||
|
@ -210,7 +210,7 @@ void AppendSymbol(struct SymbolTableEntry** Head, struct SymbolTableEntry** Tail
|
||||||
void FreeLocals() {
|
void FreeLocals() {
|
||||||
Locals = LocalsEnd = NULL;
|
Locals = LocalsEnd = NULL;
|
||||||
Params = ParamsEnd = NULL;
|
Params = ParamsEnd = NULL;
|
||||||
FunctionEntry = NULL;
|
CurrentFile->FunctionEntry = NULL;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,7 @@ int PrimitiveSize(int Type) {
|
||||||
case RET_LONG:
|
case RET_LONG:
|
||||||
return 8;
|
return 8;
|
||||||
default:
|
default:
|
||||||
DieBinary("Bad type in PrimitiveSize", Type);
|
DieDecimal("Bad type in PrimitiveSize", Type);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user