started on v2

This commit is contained in:
Sean 2020-02-14 17:08:27 -07:00
parent 9461dc4cb5
commit 0a3879f4a9
No known key found for this signature in database
GPG Key ID: B111C910D99B42B8
99 changed files with 23392 additions and 5755 deletions

1
.gitignore vendored
View File

@ -5,3 +5,4 @@ seg*
2mg
omf
regs
docmaker/docmaker

View File

@ -4,13 +4,22 @@ CFLAGS=-Wall
all: 2mg omf regs
2mg: 2mg.o
$(CC) $(CFLAGS) -o $@ $^
$(CC) $(CFLAGS) -o $@ -largp $^
omf: omf.o parser.o
$(CC) $(CFLAGS) -o $@ $^
$(CC) $(CFLAGS) -o $@ -largp $^
regs: regs.o map.o scan.o parser.o disasm.o
$(CC) $(CFLAGS) -o $@ $^
regs: regs.o map.o scan.o parser.o disasm.o iigs.o
$(CC) $(CFLAGS) -o $@ -largp $^
iigs.c: iigs.dat
xxd -i $< $@
iigs.dat: docmaker/docmaker iigs
./docmaker/docmaker iigs
docmaker/docmaker:
$(MAKE) -C docmaker
%.o: %.c
$(CC) -c $(CFLAGS) -o $@ $<

14
docmaker/Makefile Normal file
View File

@ -0,0 +1,14 @@
OBJS = docmaker.o parser.o compiler.o file.o avl.o output.o
CXX = clang++
CXXFLAGS = -Wall -std=c++11
all: docmaker
docmaker: $(OBJS)
$(CXX) $(CXXFLAGS) $(LIBS) -o $@ $^
%.o: %.cc
$(CXX) -c $(CXXFLAGS) -o $@ $<
clean:
rm -f docmaker $(OBJS)

115
docmaker/avl.cc Normal file
View File

@ -0,0 +1,115 @@
/** @copyright 2020 Sean Kasun */
#include "avl.h"
/**
This works like a combiantion self-balancing AVL tree and
Huffman tree. Basically, each node of the AVL tree contains a
sub-AVL tree of further matches (that's what the 'down' branch represents)
*/
static inline int max(int a, int b) {
return (a > b) ? a : b;
}
static inline int Height(AVLNode node) {
if (node == nullptr) {
return 0;
}
return node->height;
}
static inline int getBalance(AVLNode node) {
if (node == nullptr) {
return 0;
}
return Height(node->left) - Height(node->right);
}
static AVLNode rotateRight(AVLNode y) {
auto x = y->left;
auto t = x->right;
x->right = y;
y->left = t;
y->height = max(Height(y->left), Height(y->right)) + 1;
x->height = max(Height(x->left), Height(x->right)) + 1;
return x;
}
static AVLNode rotateLeft(AVLNode x) {
auto y = x->right;
auto t = y->left;
y->left = x;
x->right = t;
x->height = max(Height(x->left), Height(x->right)) + 1;
y->height = max(Height(y->left), Height(y->right)) + 1;
return y;
}
AVLNode AVL::insertOnce(AVLNode node, uint32_t key) {
if (node == nullptr) {
node = std::make_shared<AVLNode_>();
node->key = key;
node->left = nullptr;
node->right = nullptr;
node->down = nullptr;
node->height = 1;
node->matched = false;
return node;
}
if (key < node->key) {
node->left = insertOnce(node->left, key);
} else if (key > node->key) {
node->right = insertOnce(node->right, key);
} else { // key already exists
return node;
}
node->height = 1 + max(Height(node->left), Height(node->right));
int balance = getBalance(node);
if (balance > 1 && key < node->left->key) {
return rotateRight(node);
}
if (balance < -1 && key > node->right->key) {
return rotateLeft(node);
}
if (balance > 1 && key > node->left->key) {
node->left = rotateLeft(node->left);
return rotateRight(node);
}
if (balance < -1 && key < node->right->key) {
node->right = rotateRight(node->right);
return rotateLeft(node);
}
return node;
}
AVLNode AVL::walk(AVLNode root, uint32_t key) const {
AVLNode node = root;
if (node == nullptr) {
node = this->root;
}
while (node != nullptr && node->key != key) {
if (key < node->key) {
node = node->left;
} else {
node = node->right;
}
}
return node;
}
bool AVL::insert(const std::vector<uint32_t> &keys) {
AVLNode *parent = &root;
for (int i = 0; i < keys.size(); i++) {
*parent = insertOnce(*parent, keys[i]);
auto node = walk(*parent, keys[i]);
if (i == keys.size() - 1) {
if (node->matched) { // duplicate
return false;
}
node->matched = true;
}
parent = &node->down;
}
return true;
}

25
docmaker/avl.h Normal file
View File

@ -0,0 +1,25 @@
/** @copyright 2020 Sean Kasun */
#pragma once
#include <memory>
#include <vector>
#include <cstdint>
struct AVLNode_ {
uint32_t key;
std::shared_ptr<AVLNode_> left, right, down;
int height;
bool matched;
};
typedef std::shared_ptr<AVLNode_> AVLNode;
class AVL {
public:
bool insert(const std::vector<uint32_t> &keys);
private:
AVLNode insertOnce(AVLNode parent, uint32_t key);
AVLNode walk(AVLNode root, uint32_t key) const;
AVLNode root;
};

226
docmaker/compiler.cc Normal file
View File

@ -0,0 +1,226 @@
/** @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;
}

21
docmaker/compiler.h Normal file
View File

@ -0,0 +1,21 @@
/** @copyright 2020 Sean Kasun */
#pragma once
#include <map>
#include <string>
#include "types.h"
class Compiler {
public:
bool run(std::map<std::string, Symbol> &symbols);
private:
int numErrors;
bool calculateSizes(Symbol *s);
int32_t calcRefSize(Ref *ref, Symbol *parent);
int32_t calcStructSize(Struct *s, Symbol *parent);
int32_t calcUnionSize(Struct *s, Symbol *parent);
bool refErr(Symbol *symbol, const char *format, ...);
bool defErr(Symbol *symbol, const char *format, ...);
};

35
docmaker/docmaker.cc Normal file
View File

@ -0,0 +1,35 @@
/** @copyright 2020 Sean Kasun */
#include <iostream>
#include "parser.h"
#include "compiler.h"
#include "output.h"
int main(int argc, char **argv) {
if (argc != 2) {
std::cerr << "Usage: " << argv[0] << " <directory>" << std::endl;
return -1;
}
Parser parser;
parser.add("uint8", U8);
parser.add("uint16", U16);
parser.add("uint32", U32);
parser.add("int8", S8);
parser.add("int16", S16);
parser.add("int32", S32);
if (!parser.run(argv[1])) {
return -1;
}
Compiler compiler;
if (!compiler.run(parser.symbols)) {
return -1;
}
std::string outname;
outname = argv[1];
outname += ".dat";
Output output;
output.save(parser.symbols, outname);
return 0;
}

117
docmaker/file.cc Normal file
View File

@ -0,0 +1,117 @@
/** @copyright 2020 Sean Kasun */
#include "file.h"
void File::skipWhitespace() {
while (p < end && isspace(*p)) {
if (*p == '\n') {
curLine++;
}
p++;
}
}
Token File::token() {
skipWhitespace();
prev = p;
Token t;
t.filename = name;
t.curLine = curLine;
if (p == end) {
t.type = END;
return t;
}
char ch = *p++;
if (isalpha(ch) || ch == '_') {
t.asStr += ch;
while (p < end && (isalnum(*p) || *p == '_')) {
t.asStr += *p++;
}
t.type = checkKeywords(t.asStr);
return t;
}
if (isdigit(ch) || ch == '-') {
bool isNeg = ch == '-';
if (isdigit(ch)) {
t.asNum = ch - '0';
}
while (p < end && isdigit(*p)) {
t.asNum *= 10;
t.asNum += *p++ - '0';
}
if (isNeg) {
t.asNum = -t.asNum;
}
t.type = NUMBER;
return t;
}
if (ch == '$') {
while (p < end && isxdigit(*p)) {
t.asNum <<= 4;
if (isdigit(*p)) {
t.asNum |= *p++ - '0';
} else if (*p >= 'a' && *p <= 'f') {
t.asNum |= *p++ - 'a' + 10;
} else {
t.asNum |= *p++ - 'A' + 10;
}
}
t.type = NUMBER;
return t;
}
t.type = SYMBOL;
t.asSym = ch;
return t;
}
void File::reset() {
p = prev;
}
TokenType File::checkKeywords(std::string keyword) {
if (keyword == "enum") {
return ENUM;
} else if (keyword == "struct") {
return STRUCT;
} else if (keyword == "union") {
return UNION;
}
return VAR;
}
bool Token::expect(char ch) {
if (type != SYMBOL) {
fprintf(stderr, "Error: %s:%d: ", filename.c_str(), curLine);
fprintf(stderr, "'%c' expected\n", ch);
return false;
}
if (asSym != ch) {
fprintf(stderr, "Error: %s:%d: ", filename.c_str(), curLine);
fprintf(stderr, "'%c' expected, found '%c' instead.\n", ch, asSym);
return false;
}
return true;
}
bool Token::expect(const char *str) {
if (type == SYMBOL) {
for (const char *s = str; *s; s++) {
if (*s == asSym) {
return true;
}
}
}
fprintf(stderr, "Error: %s:%d: ", filename.c_str(), curLine);
bool comma = false;
for (const char *s = str; *s; s++) {
fprintf(stderr, "%s'%c'", comma ? " or " : "", *s);
comma = true;
}
if (type == SYMBOL) {
fprintf(stderr, " expected, found '%c' instead\n", asSym);
} else {
fprintf(stderr, " expected\n");
}
return false;
}

34
docmaker/file.h Normal file
View File

@ -0,0 +1,34 @@
/** @copyright 2020 Sean Kasun */
#pragma once
#include <string>
enum TokenType {
END, ENUM, NUMBER, SYMBOL, STRING, STRUCT, UNION, VAR,
};
struct Token {
TokenType type;
std::string asStr;
char asSym = 0;
int32_t asNum = 0;
std::string filename;
int curLine;
bool expect(char ch);
bool expect(const char *chs);
};
struct File {
char *p;
char *prev;
char *end;
std::string name;
int curLine;
Token token();
void reset();
private:
void skipWhitespace();
TokenType checkKeywords(std::string keyword);
};

143
docmaker/output.cc Normal file
View File

@ -0,0 +1,143 @@
/** @copyright 2020 Sean Kasun */
#include "output.h"
#include <fstream>
void Output::save(const std::map<std::string, Symbol> &symbols,
const std::string &filename) {
std::ofstream f(filename, std::ios::out | std::ios::binary | std::ios::trunc);
if (!f.is_open()) {
std::cerr << "Failed to create " << filename << std::endl;
exit(-1);
}
w32(&f, symbols.size());
uint32_t id = 1;
for (auto it = symbols.begin(); it != symbols.end(); it++) {
w32(&f, id);
w8(&f, it->second.kind);
ws(&f, it->first);
ids[it->first] = id++;
}
for (auto it = symbols.begin(); it != symbols.end(); it++) {
auto symbol = it->second;
w32(&f, lookup(it->first));
w32(&f, symbol.size);
switch (symbol.kind) {
case isIntrinsic:
setIntrinsic(&f, symbol.asIntrinsic);
break;
case isEnum:
setEnum(&f, symbol.asEnum);
break;
case isAlias:
setRef(&f, symbol.asAlias);
break;
case isStruct:
setStruct(&f, symbol.asStruct);
break;
case isUnion:
setStruct(&f, symbol.asStruct);
break;
case isFunction:
setFunction(&f, symbol.asFunction);
break;
default:
std::cerr << "Unknown symbol type" << std::endl;
exit(-1);
}
}
f.close();
}
uint32_t Output::lookup(const std::string &name) const {
return ids.at(name);
}
void Output::w32(std::ostream *f, uint32_t val) {
char buf[4];
buf[0] = val & 0xff;
buf[1] = (val >> 8) & 0xff;
buf[2] = (val >> 16) & 0xff;
buf[3] = (val >> 24) & 0xff;
f->write(buf, 4);
}
void Output::w8(std::ostream *f, uint8_t val) {
char v = val;
f->write(&v, 1);
}
void Output::ws(std::ostream *f, const std::string &val) {
uint8_t len = val.length() > 255 ? 255 : val.length();
char v = len;
f->write(&v, 1);
f->write(val.c_str(), len);
}
void Output::setIntrinsic(std::ostream *f, const Intrinsic i) {
w8(f, i);
}
void Output::setEnum(std::ostream *f, const Enum *e) {
w32(f, lookup(e->type->name));
w32(f, e->entries.size());
for (auto it = e->entries.begin(); it != e->entries.end(); it++) {
w32(f, it->second);
ws(f, it->first);
}
}
void Output::setRef(std::ostream *f, const Ref *r) {
if (r->symbol == nullptr) {
w32(f, 0);
} else {
w32(f, lookup(r->symbol->name));
w32(f, r->pointer);
w32(f, r->array);
ws(f, r->reg);
}
}
void Output::setStruct(std::ostream *f, const Struct *s) {
w32(f, s->fields.size());
for (auto &field : s->fields) {
setField(f, field);
}
}
void Output::setFunction(std::ostream *f, const Function *func) {
w32(f, func->arguments.size());
for (auto &arg : func->arguments) {
setArgument(f, arg);
}
setRef(f, &func->retType);
w32(f, func->signature.size());
for (auto sig : func->signature) {
w32(f, sig);
}
}
void Output::setField(std::ostream *f, const Field &field) {
ws(f, field.key);
w8(f, field.kind);
w32(f, field.size);
switch (field.kind) {
case isRef:
setRef(f, field.ref);
break;
case isStruct:
setStruct(f, field.theStruct);
break;
case isUnion:
setStruct(f, field.theStruct);
break;
default:
std::cerr << "Unknown field type" << std::endl;
exit(-1);
}
}
void Output::setArgument(std::ostream *f, const Argument &a) {
ws(f, a.key);
setRef(f, &a.ref);
}

26
docmaker/output.h Normal file
View File

@ -0,0 +1,26 @@
/** @copyright 2020 Sean Kasun */
#pragma once
#include <iostream>
#include <map>
#include "parser.h"
class Output {
public:
void save(const std::map<std::string, Symbol> &symbols,
const std::string &filename);
private:
uint32_t lookup(const std::string &name) const;
void setIntrinsic(std::ostream *f, const Intrinsic i);
void setEnum(std::ostream *f, const Enum *e);
void setRef(std::ostream *f, const Ref *r);
void setStruct(std::ostream *f, const Struct *str);
void setFunction(std::ostream *f, const Function *func);
void setField(std::ostream *f, const Field &field);
void setArgument(std::ostream *f, const Argument &arg);
void w32(std::ostream *f, uint32_t value);
void w8(std::ostream *f, uint8_t value);
void ws(std::ostream *f, const std::string &text);
std::map<std::string, uint32_t> ids;
};

342
docmaker/parser.cc Normal file
View File

@ -0,0 +1,342 @@
/** @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);
}

28
docmaker/parser.h Normal file
View File

@ -0,0 +1,28 @@
/** @copyright 2020 Sean Kasun */
#pragma once
#include <map>
#include <string>
#include "types.h"
#include "file.h"
class Parser {
public:
void add(const char *token, Intrinsic value);
bool run(std::string directory);
std::map<std::string, Symbol> symbols;
private:
Symbol *find(const Token &t);
bool load(std::string filename);
bool parse(File *file);
bool addDefinition(const Token &def, File *file);
bool parseFunc(Symbol *s, File *f);
bool parseEnum(Symbol *s, File *f);
bool parseStruct(Struct *s, File *f);
bool parseAlias(Symbol *s, File *f);
bool parseField(Field *field, const Token &def, File *f);
bool parseArgument(Argument *arg, const Token &def, File *f);
bool parseRef(Ref *ref, File *f);
void error(File *f, const char *format, ...);
};

73
docmaker/types.h Normal file
View File

@ -0,0 +1,73 @@
/** @copyright 2020 Sean Kasun */
#pragma once
#include <map>
#include <vector>
#include <string>
enum Intrinsic {
U8, U16, U32, S8, S16, S32
};
enum Kind {
isIntrinsic, isEnum, isAlias, isStruct, isUnion, isRef, isFunction
};
struct Ref {
struct Symbol *symbol = nullptr;
int32_t pointer = 0;
int32_t array = -1;
std::string reg;
};
struct Field {
std::string key;
Kind kind;
int32_t size = 0;
union {
Ref *ref;
struct Struct *theStruct;
};
};
struct Argument {
std::string key;
Ref ref;
};
struct Enum {
Symbol *type;
std::map<std::string, int32_t> entries;
};
struct Function {
std::vector<Argument> arguments;
Ref retType;
std::vector<uint32_t> signature;
};
struct Struct {
std::vector<Field> fields;
};
struct Symbol {
std::string name;
bool isSizing = false;
bool isSized = false;
int32_t size = 0;
bool isKnown = false;
int referencedLine = 0;
std::string referencedFile;
int definedLine = 0;
std::string definedFile;
Kind kind;
union {
Function *asFunction;
Struct *asStruct;
Intrinsic asIntrinsic;
Ref *asAlias;
Enum *asEnum;
};
};

14314
iigs.c Normal file

File diff suppressed because it is too large Load Diff

BIN
iigs.dat Normal file

Binary file not shown.

48
iigs/ace.txt Normal file
View File

@ -0,0 +1,48 @@
ACEErr enum<uint16> {
aceNoError = $0,
aceIsActive = $1d01,
aceBadDP = $1d02,
aceNotActive = $1d03,
aceNoSuchParam = $1d04,
aceBadMethod = $1d05,
aceBadSrc = $1d06,
aceBadDest = $1d07,
aceDataOverlap = $1d08,
aceNotImplemented = $1dff,
}
ACEBootInit() {
$1d, $01
}
ACEStartUp(dPageAddr: int16) {
$1d, $02
}
ACEShutDown() {
$1d, $03
}
ACEVersion(): int16 {
$1d, $04
}
ACEReset() {
$1d, $05
}
ACEStatus(): bool {
$1d, $06
}
ACEInfo(infoItemCode: int16): int32 {
$1d, $07
}
ACECompBegin() {
$1d, $0b
}
ACECompress(src: Handle, srcOffset: int32, dest: Handle, destOffset: int32,
nBlks: int16, method: int16) {
$1d, $09
}
ACEExpand(src: Handle, srcOffset: int32, dest: Handle, destOffset: int32,
nBlks: int16, method: int16) {
$1d, $0a
}
ACEExpBegin() {
$1d, $0c
}

127
iigs/adb.txt Normal file
View File

@ -0,0 +1,127 @@
ADBErr enum<uint16> {
cmndIncomplete = $910,
cantSync = $911,
adbBusy = $982,
devNotAtAddr = $983,
srqListFull = $984,
}
ADBCommand enum<int16> {
abort = $1,
resetKbd = $2,
flushKbd = $3,
setModes = $4,
clearModes = $5,
setConfig = $6,
synch = $7,
writeMicroMem = $8,
readMicroMem = $9,
readModes = $a,
readConfig = $b,
readADBError = $c,
readVersionNum = $d,
readAvailCharSet = $e,
readAvailLayout = $f,
resetSys = $10,
keyCode = $11,
resetADB = $40,
transmitADBBytes = $47,
enableSRQ = $50,
flushADBDevBuf = $60,
disableSRQ = $70,
listen = $80,
talk = $c0,
}
ReadConfigRecPtr = ^ReadConfigRec;
ReadConfigRec struct {
rcRepeatDelay: uint8;
rcLayoutOrLang: uint8;
rcADBAddr: uint8;
}
SetConfigRecPtr = ^SetConfigRec;
SetConfigRec struct {
scADBAddr: uint8;
scLayoutOrLang: uint8;
scRepeatDelay: uint8;
}
SynchRecPtr = ^SynchRec;
SynchRec struct {
synchMode: uint8;
synchKybdMouseAddr: uint8;
synchLayoutOrLang: uint8;
synchRepeatDelay: uint8;
}
ADBData union {
readConfig: ReadConfigRec;
setConfig: SetConfigRec;
synch: SynchRec;
raw: uint8[];
}
ScaleRecPtr = ^ScaleRec;
ScaleRec struct {
xDivide: int16;
yDivide: int16;
xOffset: int16;
yOffset: int16;
xMultiply: int16;
yMultiply: int16;
}
ADBBootInit() {
$09, $01
}
ADBStartUp() {
$09, $02
}
ADBShutDown() {
$09, $03
}
ADBVersion(): int16 {
$09, $04
}
ADBReset() {
$09, $05
}
ADBStatus(): bool {
$09, $06
}
AbsOff() {
$09, $10
}
AbsOn() {
$09, $0f
}
AsynchADBReceive(compPtr: Ptr) {
$09, $0d
}
ClearSRQTable() {
$09, $16
}
GetAbsScale(dataInPtr: ^ScaleRec) {
$09, $13
}
ReadAbs(): int16 {
$09, $11
}
ReadKeyMicroData(dataLength: int16, dataPtr: ^ADBData, adbCommand: ADBCommand) {
$09, $0a
}
ReadKeyMicroMem(dataLength: int16, dataPtr: ^ADBData, adbCommand: ADBCommand) {
$09, $0b
}
SendInfo(dataLength: int16, dataPtr: ^ADBData, adbCommand: ADBCommand) {
$09, $09
}
SetAbsScale(dataOutPtr: ^ScaleRec) {
$09, $12
}
SRQPoll(compPtr: Ptr, adbRegAddr: int16) {
$09, $14
}
SRQRemove(adbRegAddr: int16) {
$09, $15
}
SyncADBReceive(intputWord: int16, compPtr: Ptr, adbCommand: ADBCommand) {
$09, $0e
}

181
iigs/applesharefst.txt Normal file
View File