Erythro/src/Main.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);
}