mirror of
https://github.com/mrkite/regs.git
synced 2024-12-01 16:52:30 +00:00
227 lines
5.6 KiB
C++
227 lines
5.6 KiB
C++
|
/** @copyright 2020 Sean Kasun */
|
||
|
#include <stdarg.h>
|
||
|
#include <iostream>
|
||
|
#include "compiler.h"
|
||
|
#include "avl.h"
|
||
|
|
||
|
bool Compiler::run(std::map<std::string, Symbol> &symbols) {
|
||
|
numErrors = 0;
|
||
|
|
||
|
for (auto it = symbols.begin(); it != symbols.end(); it++) {
|
||
|
if (!it->second.isKnown) {
|
||
|
if (!refErr(&it->second, "Unknown type: '%s'\n",
|
||
|
it->second.name.c_str())) {
|
||
|
return false;
|
||
|
}
|
||
|
} else if (!it->second.isSized) {
|
||
|
calculateSizes(&it->second);
|
||
|
}
|
||
|
}
|
||
|
AVL avl;
|
||
|
|
||
|
// verify functions only passed 32-bits or smaller
|
||
|
// also verify functions have unique signatures
|
||
|
for (auto it = symbols.begin(); it != symbols.end(); it++) {
|
||
|
if (it->second.kind == isFunction) {
|
||
|
Function *f = it->second.asFunction;
|
||
|
for (auto arg = f->arguments.begin(); arg != f->arguments.end(); arg++) {
|
||
|
if (arg->ref.pointer == 0 &&
|
||
|
(arg->ref.symbol->size > 4 || arg->ref.array == 0)) {
|
||
|
if (!defErr(&it->second, "Argument too large: '%s'\n",
|
||
|
arg->key.c_str())) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (f->retType.symbol != nullptr && f->retType.pointer == 0 &&
|
||
|
(f->retType.symbol->size > 4 || f->retType.array >= 0)) {
|
||
|
if (!defErr(&it->second, "Return value too large on '%s'\n",
|
||
|
it->second.name.c_str())) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
if (f->signature.size() > 0) {
|
||
|
if (!avl.insert(f->signature)) {
|
||
|
if (!defErr(&it->second, "Duplicate signature on '%s'\n",
|
||
|
it->second.name.c_str())) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool Compiler::calculateSizes(Symbol *s) {
|
||
|
s->isSizing = true;
|
||
|
switch (s->kind) {
|
||
|
case isFunction:
|
||
|
s->size = 4;
|
||
|
break;
|
||
|
case isAlias:
|
||
|
case isRef:
|
||
|
s->size = calcRefSize(s->asAlias, s);
|
||
|
break;
|
||
|
case isStruct:
|
||
|
s->size = calcStructSize(s->asStruct, s);
|
||
|
if (s->size < 0) {
|
||
|
return false;
|
||
|
}
|
||
|
break;
|
||
|
case isUnion:
|
||
|
s->size = calcUnionSize(s->asStruct, s);
|
||
|
if (s->size < 0) {
|
||
|
return false;
|
||
|
}
|
||
|
break;
|
||
|
case isEnum:
|
||
|
if (!s->asEnum->type->isKnown) {
|
||
|
refErr(s->asEnum->type, "Unknown type: '%s'\n",
|
||
|
s->asEnum->type->name.c_str());
|
||
|
return false;
|
||
|
}
|
||
|
if (!s->asEnum->type->isSized) {
|
||
|
if (s->asEnum->type->isSizing) {
|
||
|
defErr(s, "Recurisve type found: '%s'\n", s->name.c_str());
|
||
|
return false;
|
||
|
}
|
||
|
if (!calculateSizes(s->asEnum->type)) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
s->size = s->asEnum->type->size;
|
||
|
break;
|
||
|
case isIntrinsic:
|
||
|
switch (s->asIntrinsic) {
|
||
|
case U8:
|
||
|
case S8:
|
||
|
s->size = 1;
|
||
|
break;
|
||
|
case U16:
|
||
|
case S16:
|
||
|
s->size = 2;
|
||
|
break;
|
||
|
case U32:
|
||
|
case S32:
|
||
|
s->size = 4;
|
||
|
break;
|
||
|
default:
|
||
|
defErr(s, "Unknown intrinsic\n");
|
||
|
return false;
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
defErr(s, "Uknown symbol type\n");
|
||
|
return false;
|
||
|
}
|
||
|
s->isSized = true;
|
||
|
s->isSizing = false;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
int32_t Compiler::calcRefSize(Ref *ref, Symbol *parent) {
|
||
|
if (!ref->symbol->isKnown) {
|
||
|
refErr(ref->symbol, "Unknown type: %s'\n", ref->symbol->name.c_str());
|
||
|
return -1;
|
||
|
}
|
||
|
// prevent recursion errors
|
||
|
if (ref->pointer > 0) {
|
||
|
return 4;
|
||
|
}
|
||
|
if (!ref->symbol->isSized) {
|
||
|
if (ref->symbol->isSizing) {
|
||
|
defErr(parent, "Recursive type found: '%s'\n", parent->name.c_str());
|
||
|
return -1;
|
||
|
}
|
||
|
if (!calculateSizes(ref->symbol)) {
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
int32_t size = ref->symbol->size;
|
||
|
if (ref->array >= 0) {
|
||
|
size *= ref->array;
|
||
|
}
|
||
|
return size;
|
||
|
}
|
||
|
|
||
|
int32_t Compiler::calcStructSize(Struct *s, Symbol *parent) {
|
||
|
int32_t size = 0;
|
||
|
for (auto it = s->fields.begin(); it != s->fields.end(); it++) {
|
||
|
switch (it->kind) {
|
||
|
case isRef:
|
||
|
it->size = calcRefSize(it->ref, parent);
|
||
|
break;
|
||
|
case isStruct:
|
||
|
it->size = calcStructSize(it->theStruct, parent);
|
||
|
break;
|
||
|
case isUnion:
|
||
|
it->size = calcUnionSize(it->theStruct, parent);
|
||
|
break;
|
||
|
default:
|
||
|
defErr(parent, "Unknown field type: '%s'\n", it->key.c_str());
|
||
|
return -1;
|
||
|
}
|
||
|
if (it->size < 0) {
|
||
|
return -1;
|
||
|
}
|
||
|
size += it->size;
|
||
|
}
|
||
|
return size;
|
||
|
}
|
||
|
|
||
|
int32_t Compiler::calcUnionSize(Struct *s, Symbol *parent) {
|
||
|
int32_t size = 0;
|
||
|
for (auto it = s->fields.begin(); it != s->fields.end(); it++) {
|
||
|
switch (it->kind) {
|
||
|
case isRef:
|
||
|
it->size = calcRefSize(it->ref, parent);
|
||
|
break;
|
||
|
case isStruct:
|
||
|
it->size = calcStructSize(it->theStruct, parent);
|
||
|
break;
|
||
|
case isUnion:
|
||
|
it->size = calcUnionSize(it->theStruct, parent);
|
||
|
break;
|
||
|
default:
|
||
|
defErr(parent, "Unknown field type: '%s'\n", it->key.c_str());
|
||
|
return -1;
|
||
|
}
|
||
|
if (it->size < 0) {
|
||
|
return -1;
|
||
|
}
|
||
|
if (it->size > size) {
|
||
|
size = it->size;
|
||
|
}
|
||
|
}
|
||
|
return size;
|
||
|
}
|
||
|
|
||
|
bool Compiler::refErr(Symbol *symbol, const char *format, ...) {
|
||
|
va_list args;
|
||
|
va_start(args, format);
|
||
|
|
||
|
fprintf(stderr, "Error: %s:%d: ", symbol->referencedFile.c_str(),
|
||
|
symbol->referencedLine);
|
||
|
vfprintf(stderr, format, args);
|
||
|
|
||
|
va_end(args);
|
||
|
|
||
|
numErrors++;
|
||
|
return numErrors < 10;
|
||
|
}
|
||
|
|
||
|
bool Compiler::defErr(Symbol *symbol, const char *format, ...) {
|
||
|
va_list args;
|
||
|
va_start(args, format);
|
||
|
|
||
|
fprintf(stderr, "Error: %s:%d: ", symbol->definedFile.c_str(),
|
||
|
symbol->definedLine);
|
||
|
vfprintf(stderr, format, args);
|
||
|
|
||
|
va_end(args);
|
||
|
|
||
|
numErrors++;
|
||
|
return numErrors < 10;
|
||
|
}
|