322 lines
9.3 KiB
C
322 lines
9.3 KiB
C
/*************/
|
|
/*GEMWIRE */
|
|
/* ERYTHRO*/
|
|
/*************/
|
|
|
|
#include <Defs.h>
|
|
#define extern_
|
|
#include <Data.h>
|
|
#undef extern_
|
|
#include <unistd.h>
|
|
|
|
|
|
int TypeSizes[5] = {0, 1, 4, 8, 0}; // in BYTES
|
|
|
|
char* TokenNames[] = {
|
|
"End of file",
|
|
"Equivalency",
|
|
|
|
"Boolean Logic OR",
|
|
"Boolean Logic AND",
|
|
|
|
"Bitwise OR",
|
|
"Bitwise XOR",
|
|
"Bitwise AND",
|
|
|
|
"Equality Check",
|
|
"Inequality Check",
|
|
"Less Than",
|
|
"Greater Than",
|
|
"Less Than or Equal",
|
|
"Greater Than or Equal",
|
|
|
|
"Left Shift",
|
|
"Right Shift",
|
|
|
|
"Addition",
|
|
"Subtraction",
|
|
"Multiplication",
|
|
"Division",
|
|
|
|
"Increment",
|
|
"Decrement",
|
|
|
|
"Statement Logical Invert",
|
|
"Bitwise Invert",
|
|
|
|
"Integer literal",
|
|
"String literal",
|
|
"Statement End",
|
|
"Colon",
|
|
|
|
"Compound Block Start",
|
|
"Compound Block End",
|
|
|
|
"Array index start",
|
|
"Array index end",
|
|
|
|
"Logical Block Start",
|
|
"Logical Block End",
|
|
|
|
"Comma",
|
|
"Dot",
|
|
"Arrow",
|
|
|
|
"Identifier",
|
|
"None Type",
|
|
"Char Type",
|
|
"Int Type",
|
|
"Long Type",
|
|
"Void Type",
|
|
|
|
"Function keyword",
|
|
"Break keyword",
|
|
"Continue keyword",
|
|
|
|
"Switch Keyword",
|
|
"Default Keyword",
|
|
"Case Keyword",
|
|
|
|
"Print Keyword",
|
|
"If keyword",
|
|
"Else keyword",
|
|
"While keyword",
|
|
"For keyword",
|
|
|
|
"Return keyword",
|
|
|
|
"Struct keyword",
|
|
"Union keyword",
|
|
"Enum keyword",
|
|
"Alias keyword",
|
|
"Import keyword"
|
|
};
|
|
|
|
char* OperationNames[] = {
|
|
"OP_ASSIGN", // Assign an l-value
|
|
"OP_BOOLOR", // Boolean OR two statements
|
|
"OP_BOOLAND", // Boolean AND two statements
|
|
"OP_BITOR", // Bitwise OR a number
|
|
"OP_BITXOR", // Bitwise XOR a number
|
|
"OP_BITAND", // Bitwise AND a number
|
|
|
|
"OP_EQUAL", // Compare equality
|
|
"OP_INEQ", // Compare inequality
|
|
"OP_LESS", // Less than?
|
|
"OP_GREAT", // Greater than?
|
|
"OP_LESSE", // Less than or Equal to?
|
|
"OP_GREATE", // Greater than or Equal to?
|
|
|
|
"OP_SHIFTL", // Arithmetic Shift Left (Multiply by 2)
|
|
"OP_SHIFTR", // Arithmetic Shift Right (Divide by 2)
|
|
"OP_ADD", // Add two numbers.
|
|
"OP_SUBTRACT", // Subtract two numbers.
|
|
"OP_MULTIPLY", // Multiply two numbers.
|
|
"OP_DIVIDE", // Divide two numbers.
|
|
|
|
"OP_PREINC", // Increment var before reference.
|
|
"OP_PREDEC", // Decrement var before reference.
|
|
"OP_POSTINC", // Increment var after reference.
|
|
"OP_POSTDEC", // Decrement var after reference.
|
|
|
|
"OP_BITNOT", // Invert a number bitwise
|
|
"OP_BOOLNOT", // Invert a statement logically
|
|
"OP_NEGATE", // Negate a number (turn a positive number negative
|
|
"OP_BOOLCONV", // Convert an expression to a boolean.s
|
|
|
|
"OP_ADDRESS", // Fetch the address of a var
|
|
"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_STRLITERAL", // String Literal. Also terminal.
|
|
|
|
"REF_IDENT", // Reference (read) an identifier (variable).
|
|
|
|
"OP_WIDEN", // Something contains a type that needs to be casted up
|
|
"OP_SCALE", // We have a pointer that needs to be scaled!
|
|
|
|
"OP_CALL", // Call a function
|
|
"OP_RET", // Return from a function
|
|
|
|
"OP_COMP", // Compound statements need a way to be 'glued' together. This is one of those mechanisms
|
|
"OP_IF", // If statement
|
|
"OP_LOOP", // FOR", WHILE
|
|
"OP_PRINT", // Print statement
|
|
|
|
"OP_FUNC", // Define a function
|
|
"OP_BREAK", // Break out of the loop
|
|
"OP_CONTINUE", // Continue the loop
|
|
"OP_SWITCH", // Switch statement
|
|
"OP_DEFAULT", // Default case
|
|
"OP_CASE" // Case
|
|
};
|
|
|
|
char* ScopeNames[] = {
|
|
"INVALID",
|
|
"GLOBAL",
|
|
"STRUCT",
|
|
"UNION",
|
|
"ENUM",
|
|
"ENUM_ENTRY",
|
|
"ALIAS",
|
|
"MEMBER",
|
|
"PARAMETER",
|
|
"LOCAL"
|
|
};
|
|
|
|
int main(int argc, char* argv[]) {
|
|
// Option initialisers
|
|
OptDumpTree = false;
|
|
OptKeepAssembly = true;
|
|
OptAssembleFiles = true;
|
|
OptLinkFiles = true;
|
|
OptVerboseOutput = false;
|
|
OptAssemblerName = "Win32";
|
|
|
|
struct FileData* InitData = malloc(sizeof(struct FileData));
|
|
InitData->CurrentLine = 0;
|
|
CurrentFile = InitData;
|
|
|
|
// Temporary .o storage and counter
|
|
int ObjectCount = 0;
|
|
|
|
// Parse command line arguments.
|
|
int i;
|
|
for (i = 1/*skip 0*/; i < argc; i++) {
|
|
// If we're not a flag, we can skip.
|
|
// We only care about flags in rows.
|
|
// ie. erc >> -v -T -o << test.exe src/main.er
|
|
if (*argv[i] != '-')
|
|
break;
|
|
|
|
// 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++) {
|
|
// Finally, identify what option is being invoked.
|
|
switch (argv[i][j]) {
|
|
case 'o': // output
|
|
OutputFileName = argv[++i];
|
|
break;
|
|
|
|
case 'T': // print Tree (debug)
|
|
OptDumpTree = true;
|
|
break;
|
|
|
|
case 'c': // Compile only
|
|
OptAssembleFiles = true;
|
|
OptKeepAssembly = false;
|
|
OptLinkFiles = false;
|
|
break;
|
|
|
|
case 'S': // aSsemble only
|
|
OptAssembleFiles = true;
|
|
OptKeepAssembly = true;
|
|
OptLinkFiles = false;
|
|
break;
|
|
|
|
case 'v': // Verbose output
|
|
OptVerboseOutput = true;
|
|
break;
|
|
|
|
case 'm': // Specify Assembler Module
|
|
OptAssemblerName = argv[++i];
|
|
break;
|
|
|
|
default:
|
|
DisplayUsage(argv[0]);
|
|
}
|
|
}
|
|
}
|
|
|
|
// If we didn't provide anything other than flags, we need to show how to use the program.
|
|
if (i >= argc)
|
|
DisplayUsage(argv[0]);
|
|
|
|
int StartOfFiles = i;
|
|
// Allocate enough files for the full specified source code
|
|
Files = malloc(sizeof(struct FileData*) * (argc - i) + 1);
|
|
memset(Files, 0, sizeof(struct FileData*) * (argc - i) + 1);
|
|
|
|
RegisterAllModules();
|
|
|
|
// For the rest of the files specified, we can iterate them right to left.
|
|
while (i < argc) {
|
|
// Prepare the source metadata before we start compiling
|
|
struct FileData* Source = malloc(sizeof(struct FileData));
|
|
memset(Source, 0, sizeof(struct FileData));
|
|
Source->SourceName = argv[i];
|
|
Source->AllowDefinitions = true;
|
|
printf("Compiling file %d (%s)\n", i - StartOfFiles, argv[i]);
|
|
Files[i - StartOfFiles] = Source;
|
|
|
|
// Compile the file by invoking the Delegate
|
|
Compile(Source);
|
|
if (OptLinkFiles || OptAssembleFiles) {
|
|
// If we need to assemble (or link, which requires assembly)
|
|
// then we invoke the Delegate again
|
|
Assemble(Source);
|
|
}
|
|
|
|
if (!OptKeepAssembly)
|
|
// unlink = delete
|
|
unlink(Source->AssemblyName);
|
|
|
|
i++;
|
|
}
|
|
|
|
if (OptLinkFiles) {
|
|
// If needed, invoke the Delegate one last time.
|
|
Link(OutputFileName, Files, (argc - StartOfFiles) + 1);
|
|
if (!OptAssembleFiles) {
|
|
// Even though we need to assemble to link, we can respect the user's options and delete the intermediary files.
|
|
for (i = 0; i < (argc - StartOfFiles) + 1; i++) {
|
|
unlink(Files[i]->AssemblyName);
|
|
unlink(Files[i]->ObjectName);
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
/*
|
|
* Akin to a Halt and Catch Fire method.
|
|
* Simply prints an error, cleans up handles, and closes.
|
|
*/
|
|
|
|
void Die(char* Error) {
|
|
fprintf(stderr, "%s on line %ld\n", Error, CurrentFile->CurrentLine);
|
|
fclose(OutputFile);
|
|
unlink(OutputFileName);
|
|
exit(1);
|
|
}
|
|
|
|
/*
|
|
* A variant of Die with an extra String attached.
|
|
*/
|
|
void DieMessage(char* Error, char* Reason) {
|
|
fprintf(stderr, "%s: %s on line %ld\n", Error, Reason, CurrentFile->CurrentLine);
|
|
fclose(OutputFile);
|
|
unlink(OutputFileName);
|
|
exit(1);
|
|
}
|
|
|
|
/*
|
|
* A variant of Die with an extra integer attached.
|
|
*/
|
|
void DieDecimal(char* Error, int Number) {
|
|
fprintf(stderr, "%s: %d on line %ld\n", Error, Number, CurrentFile->CurrentLine);
|
|
fclose(OutputFile);
|
|
unlink(OutputFileName);
|
|
exit(1);
|
|
}
|
|
|
|
/*
|
|
* A variant of Die with an extra character attached.
|
|
*/
|
|
void DieChar(char* Error, int Char) {
|
|
fprintf(stderr, "%s: %c on line %ld\n", Error, Char, CurrentFile->CurrentLine);
|
|
fclose(OutputFile);
|
|
unlink(OutputFileName);
|
|
exit(1);
|
|
} |