mirror of
https://github.com/mrkite/regs.git
synced 2024-12-01 16:52:30 +00:00
343 lines
7.6 KiB
C++
343 lines
7.6 KiB
C++
/** @copyright 2020 Sean Kasun */
|
|
|
|
#include <dirent.h>
|
|
#include <stdarg.h>
|
|
#include <iostream>
|
|
#include <fstream>
|
|
#include <utility>
|
|
|
|
#include "parser.h"
|
|
|
|
void Parser::add(const char *token, Intrinsic value) {
|
|
Token t;
|
|
t.asStr = token;
|
|
t.filename = "(intrinsic)";
|
|
t.curLine = 0;
|
|
Symbol *symbol = find(t);
|
|
symbol->isKnown = true;
|
|
symbol->definedLine = symbol->referencedLine;
|
|
symbol->definedFile = symbol->referencedFile;
|
|
symbol->kind = isIntrinsic;
|
|
symbol->asIntrinsic = value;
|
|
}
|
|
|
|
bool Parser::run(std::string directory) {
|
|
DIR *dir = opendir(directory.c_str());
|
|
if (!dir) {
|
|
std::cerr << "Couldn't open directory: " << directory << std::endl;
|
|
return false;
|
|
}
|
|
struct dirent *file;
|
|
while ((file = readdir(dir)) != nullptr) {
|
|
if (file->d_name[0] == '.') {
|
|
continue;
|
|
}
|
|
std::string filename = directory + "/" + file->d_name;
|
|
if (!load(filename)) {
|
|
closedir(dir);
|
|
return false;
|
|
}
|
|
}
|
|
closedir(dir);
|
|
return true;
|
|
}
|
|
|
|
Symbol *Parser::find(const Token &t) {
|
|
std::string key = t.asStr;
|
|
if (symbols.count(key) == 0) {
|
|
Symbol s;
|
|
s.name = key;
|
|
s.referencedLine = t.curLine;
|
|
s.referencedFile = t.filename;
|
|
symbols.insert(std::pair<std::string, Symbol>(key, s));
|
|
}
|
|
return &symbols[key];
|
|
}
|
|
|
|
bool Parser::load(std::string filename) {
|
|
std::ifstream f(filename, std::ios::in | std::ios::binary | std::ios::ate);
|
|
if (!f.is_open()) {
|
|
return false;
|
|
}
|
|
std::streamoff len = f.tellg();
|
|
char *data = new char[len + 1];
|
|
f.seekg(0, std::ios::beg);
|
|
f.read(data, len);
|
|
f.close();
|
|
|
|
data[len] = 0;
|
|
|
|
File file;
|
|
file.p = data;
|
|
file.end = data + len;
|
|
file.name = filename;
|
|
file.curLine = 1;
|
|
|
|
bool okay = parse(&file);
|
|
delete [] data;
|
|
return okay;
|
|
}
|
|
|
|
bool Parser::parse(File *file) {
|
|
Token token;
|
|
while ((token = file->token()).type != END) {
|
|
switch (token.type) {
|
|
case VAR:
|
|
if (!addDefinition(token, file)) {
|
|
return false;
|
|
}
|
|
break;
|
|
default:
|
|
error(file, "Expected a definition\n");
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool Parser::addDefinition(const Token &def, File *file) {
|
|
Symbol *s = find(def);
|
|
if (s->isKnown) {
|
|
error(file, "Duplicate definition: '%s'\nDefined in '%s' on line %d\n",
|
|
s->name.c_str(), s->definedFile.c_str(), s->definedLine);
|
|
return false;
|
|
}
|
|
s->definedLine = def.curLine;
|
|
s->definedFile = def.filename;
|
|
s->isKnown = true;
|
|
Token token = file->token();
|
|
switch (token.type) {
|
|
case ENUM:
|
|
return parseEnum(s, file);
|
|
case SYMBOL:
|
|
switch (token.asSym) {
|
|
case '(':
|
|
return parseFunc(s, file);
|
|
case '=':
|
|
return parseAlias(s, file);
|
|
default:
|
|
error(file, "Expected '=' or '(', found '%c'\n", token.asSym);
|
|
return false;
|
|
}
|
|
case STRUCT:
|
|
s->kind = isStruct;
|
|
s->asStruct = new Struct();
|
|
return parseStruct(s->asStruct, file);
|
|
case UNION:
|
|
s->kind = isUnion;
|
|
s->asStruct = new Struct();
|
|
return parseStruct(s->asStruct, file);
|
|
default:
|
|
error(file, "Parser error.\n");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool Parser::parseEnum(Symbol *s, File *f) {
|
|
Enum *e = new Enum();
|
|
s->kind = isEnum;
|
|
s->asEnum = e;
|
|
if (!f->token().expect('<')) {
|
|
return false;
|
|
}
|
|
Token token = f->token();
|
|
if (token.type != VAR) {
|
|
error(f, "Expected a type name\n");
|
|
return false;
|
|
}
|
|
e->type = find(token);
|
|
if (!f->token().expect('>')) {
|
|
return false;
|
|
}
|
|
if (!f->token().expect('{')) {
|
|
return false;
|
|
}
|
|
int32_t prevVal = -1;
|
|
while ((token = f->token()).type == VAR) {
|
|
std::string key = token.asStr;
|
|
token = f->token();
|
|
if (token.type == SYMBOL && token.asSym == '=') {
|
|
prevVal = f->token().asNum;
|
|
token = f->token();
|
|
} else {
|
|
prevVal++;
|
|
}
|
|
e->entries.insert(std::pair<std::string, int32_t>(key, prevVal));
|
|
if (!token.expect(",}")) {
|
|
return false;
|
|
}
|
|
if (token.asSym == '}') {
|
|
break;
|
|
}
|
|
}
|
|
return token.expect('}');
|
|
}
|
|
|
|
bool Parser::parseFunc(Symbol *s, File *f) {
|
|
Function *func = new Function();
|
|
s->kind = isFunction;
|
|
s->asFunction = func;
|
|
|
|
Token token;
|
|
while ((token = f->token()).type == VAR) {
|
|
Argument arg;
|
|
if (!parseArgument(&arg, token, f)) {
|
|
return false;
|
|
}
|
|
func->arguments.push_back(arg);
|
|
token = f->token();
|
|
if (!token.expect(",)")) {
|
|
return false;
|
|
}
|
|
if (token.asSym == ')') {
|
|
break;
|
|
}
|
|
}
|
|
if (!token.expect(')')) {
|
|
return false;
|
|
}
|
|
token = f->token();
|
|
if (!token.expect(":;{")) {
|
|
return false;
|
|
}
|
|
func->retType.symbol = nullptr;
|
|
if (token.asSym == ':') {
|
|
if (!parseRef(&func->retType, f)) {
|
|
return false;
|
|
}
|
|
token = f->token();
|
|
if (!token.expect(";{")) {
|
|
return false;
|
|
}
|
|
}
|
|
if (token.asSym == '{') {
|
|
while ((token = f->token()).type == NUMBER) {
|
|
func->signature.push_back(token.asNum);
|
|
token = f->token();
|
|
if (!token.expect(",}")) {
|
|
return false;
|
|
}
|
|
if (token.asSym == '}') {
|
|
break;
|
|
}
|
|
}
|
|
if (!token.expect('}')) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool Parser::parseAlias(Symbol *s, File *f) {
|
|
Ref *ref = new Ref();
|
|
s->asAlias = ref;
|
|
s->kind = isAlias;
|
|
if (!parseRef(ref, f)) {
|
|
return false;
|
|
}
|
|
return f->token().expect(';');
|
|
}
|
|
|
|
bool Parser::parseStruct(Struct *s, File *f) {
|
|
if (!f->token().expect('{')) {
|
|
return false;
|
|
}
|
|
Token token;
|
|
while ((token = f->token()).type == VAR || token.type == STRUCT ||
|
|
token.type == UNION) {
|
|
Field field;
|
|
if (!parseField(&field, token, f)) {
|
|
return false;
|
|
}
|
|
s->fields.push_back(field);
|
|
token = f->token();
|
|
if (!token.expect(";}")) {
|
|
return false;
|
|
}
|
|
if (token.asSym == '}') {
|
|
break;
|
|
}
|
|
}
|
|
return token.expect('}');
|
|
}
|
|
|
|
bool Parser::parseArgument(Argument *arg, const Token &def, File *f) {
|
|
arg->key = def.asStr;
|
|
if (!f->token().expect(':')) {
|
|
return false;
|
|
}
|
|
return parseRef(&arg->ref, f);
|
|
}
|
|
|
|
bool Parser::parseRef(Ref *ref, File *f) {
|
|
ref->pointer = 0;
|
|
ref->array = -1;
|
|
|
|
Token token;
|
|
while ((token = f->token()).type == SYMBOL && token.asSym == '^') {
|
|
ref->pointer++;
|
|
}
|
|
if (token.type != VAR) {
|
|
error(f, "Expected a type or a pointer.\n");
|
|
return false;
|
|
}
|
|
ref->symbol = find(token);
|
|
token = f->token();
|
|
if (token.type == SYMBOL && token.asSym == '[') {
|
|
ref->array = 0; // empty bracket
|
|
token = f->token();
|
|
if (token.type == NUMBER) {
|
|
ref->array = token.asNum;
|
|
token = f->token();
|
|
}
|
|
if (!token.expect(']')) {
|
|
return false;
|
|
}
|
|
} else {
|
|
f->reset();
|
|
}
|
|
token = f->token();
|
|
if (token.type == SYMBOL && token.asSym == '|') {
|
|
token = f->token();
|
|
if (token.type != VAR) {
|
|
error(f, "Expected a register\n");
|
|
return false;
|
|
} else {
|
|
ref->reg = token.asStr;
|
|
}
|
|
} else {
|
|
f->reset();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool Parser::parseField(Field *field, const Token &def, File *f) {
|
|
if (def.type == STRUCT) {
|
|
field->kind = isStruct;
|
|
field->theStruct = new Struct();
|
|
return parseStruct(field->theStruct, f);
|
|
} else if (def.type == UNION) {
|
|
field->kind = isUnion;
|
|
field->theStruct = new Struct();
|
|
return parseStruct(field->theStruct, f);
|
|
} else {
|
|
field->kind = isRef;
|
|
field->key = def.asStr;
|
|
if (!f->token().expect(':')) {
|
|
return false;
|
|
}
|
|
field->ref = new Ref();
|
|
return parseRef(field->ref, f);
|
|
}
|
|
}
|
|
|
|
void Parser::error(File *f, const char *format, ...) {
|
|
va_list args;
|
|
va_start(args, format);
|
|
|
|
fprintf(stderr, "Error: %s:%d: ", f->name.c_str(), f->curLine);
|
|
vfprintf(stderr, format, args);
|
|
|
|
va_end(args);
|
|
}
|