diff --git a/compiler.h b/compiler.h index 23dcf0f..6a09028 100644 --- a/compiler.h +++ b/compiler.h @@ -10,6 +10,6 @@ typedef struct { } COMPILER; COMPILER* mkcompiler(CLASS* classes); -void compile(); +void compile(COMPILER* c); #endif diff --git a/parser-constants.h b/parser-constants.h deleted file mode 100644 index ababf04..0000000 --- a/parser-constants.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef PARSER_CONSTANTS_H -#define PARSER_CONSTANTS_H -#include "util.h" - -const char* keywordsarr[] = { "true", "false", "null", "this" }; -const char* opsarr[] = { "+", "-", "*", "/", "&", "|", "<", ">", "=" }; -const char* classvartypesarr[] = { "static", "field" }; -const char* vartypesarr[] = { "int", "char", "boolean" }; -const char* subroutclassesarr[] = { "constructor", "function", "method" }; -const char* tokentypesarr[] = { "keyword", "identifier", "symbol", "integerConstant", "stringConstant" }; - -#define mkstrlist(name, array) STRINGARRAY name = { .items = array, .size = strcount(array) } -mkstrlist(keywordconstants, keywordsarr); -mkstrlist(operators, opsarr); -mkstrlist(classvartypes, classvartypesarr); -mkstrlist(vartypes, vartypesarr); -mkstrlist(subroutclasses, subroutclassesarr); -mkstrlist(tokentypes, tokentypesarr); -#undef mkstrlist -#endif diff --git a/parser-expressions.c b/parser-expressions.c new file mode 100644 index 0000000..474659f --- /dev/null +++ b/parser-expressions.c @@ -0,0 +1,238 @@ +#include +#include "util.h" +#include "parser-internal.h" +#include "parser-expressions.h" + +TERM* parsetermnullified(PARSER* p); +TERM* parseterm(PARSER* p); +TERM* mkterm(TERMTYPE type); +TERM* parseint(PARSER* p); +TERM* parsestr(PARSER* p); +TERM* parsekeyword(PARSER* p); +TERM* parseunaryopterm(PARSER* p); +TERM* parseinnerexpression(PARSER* p); +TERM* parsecalltermnullified(PARSER* p); +TERM* parsearrayterm(PARSER* p); +TERM* parsevarterm(PARSER* p); +TERM* parseidentifierterm(PARSER* p); +bool isop(TOKEN* t); +SUBROUTCALL* nullsubroutcall(PARSER* p, SUBROUTCALL* c); +SUBROUTCALL* parsesubroutcallnullified(PARSER* p); + +const char* keywordsarr[] = { "true", "false", "null", "this" }; +const char* opsarr[] = { "+", "-", "*", "/", "&", "|", "<", ">", "=" }; +mkstrlist(keywordconstants, keywordsarr); +mkstrlist(operators, opsarr); + +TERM* parsetermnullified(PARSER* p) { + TOKENTYPE type = p->current->type; + if(type == integer) + return parseint(p); + else if(type == string) + return parsestr(p); + else if(type == keyword) + return parsekeyword(p); + else if(type == identifier) + return parseidentifierterm(p); + else if(equals(p, "-") || equals(p, "~")) + return parseunaryopterm(p); + else if(equals(p, "(")) + return parseinnerexpression(p); + return NULL; +} + +TERM* parseterm(PARSER* p) { + TERM* t = parsetermnullified(p); + if(t == NULL) + unexpected(p); + return t; +} + +TERM* mkterm(TERMTYPE type) { + TERM* t = (TERM*)malloc(sizeof(TERM)); + t->type = type; + return t; +} + +TERM* parseint(PARSER* p) { + TERM* t = mkterm(intconstant); + t->integer = atoi(p->current->token); + next(p); + return t; +} + +TERM* parsestr(PARSER* p) { + TERM* t = mkterm(stringconstant); + t->string = p->current->token; + next(p); + return t; +} + +TERM* parsekeyword(PARSER* p) { + TERM* t = mkterm(keywordconstant); + if(!existsinarray(&keywordconstants, p->current->token)) + unexpected(p); + t->string = p->current->token; + next(p); + return t; +} + +TERM* parseunaryopterm(PARSER* p) { + TERM* t = mkterm(unaryopterm); + next(p); + t->expression = parseterm(p); + t->expression->next = NULL; + return t; +} + +TERM* parseinnerexpression(PARSER* p) { + TERM* t = mkterm(innerexpression); + next(p); + t->expression = parseexpression(p); + checkcontent(p, ")"); + return t; +} + +TERM* parsecalltermnullified(PARSER* p) { + TERM* t = mkterm(subroutcall); + SUBROUTCALL* call = parsesubroutcallnullified(p); + t->call == call; + return t; +} + +TERM* parsearrayterm(PARSER* p) { + TERM* t = mkterm(arrayitem); + t->string = p->current->token; + next(p); + checkcontent(p, "["); + t->arrayexp = parseexpression(p); + checkcontent(p, "]"); + return t; +} + +TERM* parsevarterm(PARSER* p) { + TERM* t = mkterm(varname); + t->string = p->current->token; + next(p); + return t; +} + +TERM* parseidentifierterm(PARSER* p) { + TERM* t = parsecalltermnullified(p); + if(t == NULL) + if(nextequals(p, "[")) + return parsearrayterm(p); + else + return parsevarterm(p); + else + return t; +} + +bool isop(TOKEN* t) { + for(int i = 0; i < operators.size; i++) + if(!strcmp(t->token, operators.items[i])) + return true; + return false; +} + +TERM* parseexpressionnullified(PARSER* p) { + TERM* head = parsetermnullified(p); + TERM* current = head; + TERM* nextt; + while(isop(p->current)) { + current->op = p->current->token[0]; + next(p); + nextt = parseterm(p); + current->next = nextt; + current = nextt; + } + if(current != NULL) + current->next = NULL; + return head; +} + +TERM* parseexpression(PARSER* p) { + TERM* t = parseexpressionnullified(p); + if(t == NULL) + unexpected(p); + return t; +} + +SUBROUTCALL* nullsubroutcall(PARSER* p, SUBROUTCALL* c) { + free(c); + rewindparser(p); + return NULL; +} + +SUBROUTCALL* parsesubroutcallnullified(PARSER* p) { + if(p->current->type != identifier) + return NULL; + + anchorparser(p); + SUBROUTCALL* c = (SUBROUTCALL*)malloc(sizeof(SUBROUTCALL)); + + c->debug = getdebug(p); + + if(nextequals(p, ".")) { + c->parentname = p->current->token; + next(p); + next(p); + } + else + c->parentname = NULL; + + if(p->current->type != identifier) + return nullsubroutcall(p, c); + c->name = p->current->token; + + if(differs(p, "(")) + return nullsubroutcall(p, c); + next(p); + + c->parameters = parseexpressionlist(p); + + if(differs(p, ")")) + return nullsubroutcall(p, c); + next(p); + return c; +} + +SUBROUTCALL* parsesubroutcall(PARSER* p) { + SUBROUTCALL* c = (SUBROUTCALL*)malloc(sizeof(SUBROUTCALL)); + c->debug = getdebug(p); + + if(nextequals(p, ".")) { + c->parentname = parseidentifier(p); + next(p); + } + else + c->parentname = NULL; + + c->name = parseidentifier(p); + + checkcontent(p, "("); + + c->parameters = parseexpressionlist(p); + + checkcontent(p, ")"); + return c; +} + +EXPRESSIONLIST* parseexpressionlist(PARSER* p) { + if(!strcmp(p->current->token, ")")) + return NULL; + EXPRESSIONLIST* head = (EXPRESSIONLIST*)malloc(sizeof(EXPRESSIONLIST)); + head->expression = parseexpressionnullified(p); + EXPRESSIONLIST* current = head; + EXPRESSIONLIST* nextls; + while(!strcmp(p->current->token, ",")) { + next(p); + nextls = (EXPRESSIONLIST*)malloc(sizeof(EXPRESSIONLIST)); + nextls->expression = parseexpression(p); + current->next = nextls; + current = nextls; + } + if(current != NULL) + current->next = NULL; + return head; +} diff --git a/parser-expressions.h b/parser-expressions.h new file mode 100644 index 0000000..9e606f1 --- /dev/null +++ b/parser-expressions.h @@ -0,0 +1,8 @@ +#ifndef PARSER_EXPRESSIONS_H +#define PARSER_EXPRESSIONS_H +#include "parser.h" +TERM* parseexpressionnullified(PARSER* p); +TERM* parseexpression(PARSER* p); +SUBROUTCALL* parsesubroutcall(PARSER* p); +EXPRESSIONLIST* parseexpressionlist(PARSER* p); +#endif diff --git a/parser-internal.c b/parser-internal.c new file mode 100644 index 0000000..cf55eec --- /dev/null +++ b/parser-internal.c @@ -0,0 +1,44 @@ +#include +#include "parser-internal.h" +#include "util.h" + + +const char* tokentypesarr[] = { "keyword", "identifier", "symbol", + "integerConstant", "stringConstant" }; +mkstrlist(tokentypes, tokentypesarr); + +void unexpected(PARSER* p) { + eprintf("Unexpected token '%s' (of type %s); line %i, file '%s'\n", + p->current->token, tokentypes.items[p->current->type], + p->current->definedat, p->file); + exit(1); +} + +void checktype(PARSER* p, TOKENTYPE type) { + if(p->current->type != type) { + eprintf("Unexpected %s; file '%s', line %i\n", + tokentypes.items[p->current->type], p->file, + p->current->definedat); + exit(1); + } +} + +void checkcontent(PARSER* p, const char* content) { + if(differs(p, content)) + unexpected(p); + next(p); +} + +char* parseidentifier(PARSER* p) { + checktype(p, identifier); + char* result = p->current->token; + next(p); + return result; +} + +DEBUGINFO* getdebug(PARSER* p) { + DEBUGINFO* d = (DEBUGINFO*)malloc(sizeof(DEBUGINFO)); + d->file = p->file; + d->definedat = p->current->definedat; + return d; +} diff --git a/parser-internal.h b/parser-internal.h new file mode 100644 index 0000000..d1b4951 --- /dev/null +++ b/parser-internal.h @@ -0,0 +1,19 @@ +#ifndef PARSER_INTERNAL_H +#define PARSER_INTERNAL_H +#include +#include "parser.h" + +#define mkstrlist(name, array) STRINGARRAY name = { .items = array, .size = strcount(array) } +#define next(parser) parser->current = p->current->next +#define rewindparser(parser) p->checkpoint = p->current +#define anchorparser(parser) p->current = p->checkpoint +#define differs(parser, str) strcmp(parser->current->token, str) +#define nextdiffers(parser, str) strcmp(parser->current->next->token, str) +#define equals(parser, str) !differs(parser, str) +#define nextequals(parser, str) !nextdiffers(parser, str) + +void unexpected(PARSER* p); +char* parseidentifier(PARSER* p); +void checkcontent(PARSER* p, const char* content); +DEBUGINFO* getdebug(PARSER* p); +#endif diff --git a/parser-statements.c b/parser-statements.c new file mode 100644 index 0000000..625796b --- /dev/null +++ b/parser-statements.c @@ -0,0 +1,136 @@ +#include +#include "parser-expressions.h" +#include "parser-internal.h" +#include "parser-statements.h" + +STATEMENT* mkstatement(STATEMENTTYPE t); +STATEMENT* parsestatementnullified(PARSER* p); +STATEMENT* parselet(PARSER* p); +CONDSTATEMENT* parsecond(PARSER* p); +STATEMENT* parseif(PARSER* p); +STATEMENT* parsewhile(PARSER* p); +STATEMENT* parsedo(PARSER* p); +STATEMENT* parsereturn(PARSER* p); + +STATEMENT* mkstatement(STATEMENTTYPE t) { + STATEMENT* s = (STATEMENT*)malloc(sizeof(STATEMENT)); + s->type = t; + return s; +} + +// Though nullified, will throw errors if the parsing was on-going +STATEMENT* parsestatementnullified(PARSER* p) { + if(equals(p, "let")) + return parselet(p); + else if(equals(p, "if")) + return parseif(p); + else if(equals(p, "while")) + return parsewhile(p); + else if(equals(p, "do")) + return parsedo(p); + else if(equals(p, "return")) + return parsereturn(p); + return NULL; +} + +STATEMENT* parsestatements(PARSER* p) { + STATEMENT* head = parsestatementnullified(p); + STATEMENT* curr = head; + STATEMENT* next; + while(next = parsestatementnullified(p), next != NULL) { + curr->next = next; + curr = next; + } + if(curr != NULL) + curr->next = NULL; + return head; +} + +STATEMENT* parselet(PARSER* p) { + next(p); + STATEMENT* s = mkstatement(letstatement); + LETSTATEMENT* letst= (LETSTATEMENT*)malloc(sizeof(LETSTATEMENT)); + + letst->varname = parseidentifier(p); + + if(equals(p, "[")) { + next(p); + letst->arrayind = parseexpression(p); + checkcontent(p, "]"); + } + else + letst->arrayind = NULL; + + checkcontent(p, "="); + + letst->expression = parseexpression(p); + + checkcontent(p, ";"); + + s->type = letstatement; + return s; +} + +CONDSTATEMENT* parsecond(PARSER* p) { + checkcontent(p, "("); + + CONDSTATEMENT* st = (CONDSTATEMENT*)malloc(sizeof(CONDSTATEMENT)); + + st->expression = parseexpression(p); + + checkcontent(p, ")"); + checkcontent(p, "{"); + + st->statements = parsestatements(p); + + checkcontent(p, "}"); + return st; +} + +STATEMENT* parseif(PARSER* p) { + next(p); + STATEMENT* s = mkstatement(ifstatement); + IFSTATEMENT* ifst = (IFSTATEMENT*)malloc(sizeof(IFSTATEMENT)); + + ifst->base = parsecond(p); + + if(equals(p, "else")) { + next(p); + checkcontent(p, "{"); + ifst->elsestatements = parsestatements(p); + checkcontent(p, "}"); + } + else + ifst->elsestatements = NULL; + + s->type = ifstatement; + return s; +} + +STATEMENT* parsewhile(PARSER* p) { + next(p); + STATEMENT* s = mkstatement(whilestatement); + + s->whilestatement = parsecond(p); + return s; +} + +STATEMENT* parsedo(PARSER* p) { + next(p); + STATEMENT* s = mkstatement(dostatement); + + s->dostatement = parsesubroutcall(p); + + checkcontent(p, ";"); + return s; +} + +STATEMENT* parsereturn(PARSER* p) { + next(p); + STATEMENT* s = mkstatement(returnstatement); + + s->retstatement = parseexpressionnullified(p); + + checkcontent(p, ";"); + return s; +} diff --git a/parser-statements.h b/parser-statements.h new file mode 100644 index 0000000..af093b0 --- /dev/null +++ b/parser-statements.h @@ -0,0 +1,5 @@ +#ifndef PARSER_STATEMENTS_H +#define PARSER_STATEMENTS_H +#include "parser.h" +STATEMENT* parsestatements(PARSER* p); +#endif diff --git a/parser-structure.c b/parser-structure.c new file mode 100644 index 0000000..9d3eb8b --- /dev/null +++ b/parser-structure.c @@ -0,0 +1,244 @@ +#include +#include "parser-internal.h" +#include "parser-structure.h" +#include "parser-statements.h" + +CLASS* parseclass(PARSER* p); +int parsepossibilities(PARSER* p, STRINGARRAY* poss); +CLASSVARTYPE parseclassvartype(PARSER* p); +CLASSVARDEC* parseclassvardec(PARSER* p); +CLASSVARDEC* parseclassvardecs(PARSER* p); +SUBROUTCLASS parsesubroutclass(PARSER* p); +SUBROUTDEC* parsesubroutdec(PARSER* p); +SUBROUTDEC* parsesubroutdecs(PARSER* p); +PARAMETER* parseparameter(PARSER* p); +PARAMETER* parseparameters(PARSER* p); +SUBROUTBODY* parsesubroutbody(PARSER* p); +bool isprimitive(TOKEN* tk); +char* parsetype(PARSER* p); +void parsevardeccommon(PARSER* p, VARDEC* v); +VARDEC* parsevardec(PARSER* p); +VARDEC* parsevardecs(PARSER* p); + +const char* classvartypesarr[] = { "static", "field" }; +const char* vartypesarr[] = { "int", "char", "boolean" }; +const char* subroutclassesarr[] = { "constructor", "function", "method" }; +mkstrlist(classvartypes, classvartypesarr); +mkstrlist(vartypes, vartypesarr); +mkstrlist(subroutclasses, subroutclassesarr); + +CLASS* parseclass(PARSER* p) { + checkcontent(p, "class"); + + CLASS* class = (CLASS*)malloc(sizeof(CLASS)); + + class->debug = getdebug(p); + + class->name = parseidentifier(p); + + checkcontent(p, "{"); + + class->vardecs = parseclassvardecs(p); + + class->subroutdecs = parsesubroutdecs(p); + + checkcontent(p, "}"); + return class; +} + +CLASS* parseclasses(PARSER* p) { + CLASS* head = parseclass(p); + CLASS* curr = head; + while(p->current != NULL && equals(p, "class")) { + curr->next = parseclass(p); + curr = curr->next; + } + if(curr != NULL) + curr->next = NULL; + return head; +} + +int parsepossibilities(PARSER* p, STRINGARRAY* poss) { + for(int i = 0; i < poss->size; i++) + if(!strcmp(p->current->token, poss->items[i])) + return i; + return -1; +} + +CLASSVARTYPE parseclassvartype(PARSER* p) { + return parsepossibilities(p, &classvartypes); +} + +CLASSVARDEC* parseclassvardec(PARSER* p) { + CLASSVARTYPE classvartype = parseclassvartype(p); + if(classvartype == -1) + return NULL; + next(p); + + CLASSVARDEC* classvardec = (CLASSVARDEC*)malloc(sizeof(CLASSVARDEC)); + classvardec->type = classvartype; + + classvardec->base = (VARDEC*)malloc(sizeof(VARDEC)); + + parsevardeccommon(p, classvardec->base); + + return classvardec; +} + +CLASSVARDEC* parseclassvardecs(PARSER* p) { + CLASSVARDEC* head = parseclassvardec(p); + CLASSVARDEC* curr = head; + CLASSVARDEC* next; + while(next = parseclassvardec(p), next != NULL) { + curr->next = next; + curr= next; + } + if(curr != NULL) + curr->next = NULL; + return head; +} + +SUBROUTCLASS parsesubroutclass(PARSER* p) { + return parsepossibilities(p, &subroutclasses); +} + +SUBROUTDEC* parsesubroutdec(PARSER* p) { + SUBROUTCLASS subroutclass = parsesubroutclass(p); + if(subroutclass == -1) + return NULL; + + next(p); + SUBROUTDEC* subroutdec = (SUBROUTDEC*)malloc(sizeof(SUBROUTDEC)); + subroutdec->subroutclass = subroutclass; + + subroutdec->typeclass = p->current->type; + if(equals(p, "void")) { + subroutdec->type = p->current->token; + next(p); + } + else + subroutdec->type = parsetype(p); + + subroutdec->debug = getdebug(p); + + subroutdec->name = parseidentifier(p); + + checkcontent(p, "("); + subroutdec->parameters = parseparameters(p); + checkcontent(p, ")"); + + checkcontent(p, "{"); + subroutdec->body = parsesubroutbody(p); + checkcontent(p, "}"); + + return subroutdec; +} + +SUBROUTDEC* parsesubroutdecs(PARSER* p) { + SUBROUTDEC* head = parsesubroutdec(p); + SUBROUTDEC* curr = head; + SUBROUTDEC* next; + while(next = parsesubroutdec(p), next != NULL) { + curr->next = next; + curr = next; + } + if(curr != NULL) + curr->next = NULL; + return head; +} + +PARAMETER* parseparameter(PARSER* p) { + PARAMETER* param = (PARAMETER*)malloc(sizeof(PARAMETER)); + if(equals(p, ")")) + return NULL; + param->type = parsetype(p); + param->name = parseidentifier(p); + return param; +} + +PARAMETER* parseparameters(PARSER* p) { + PARAMETER* head = parseparameter(p); + PARAMETER* curr = head; + while(equals(p, ",")) { + next(p); + curr->next = parseparameter(p); + curr = curr->next; + } + if(curr != NULL) + curr->next = NULL; + return head; +} + +SUBROUTBODY* parsesubroutbody(PARSER* p) { + SUBROUTBODY* subroutbody = (SUBROUTBODY*)malloc(sizeof(SUBROUTBODY)); + subroutbody->vardecs = parsevardecs(p); + subroutbody->statements = parsestatements(p); + + return subroutbody; +} + +bool isprimitive(TOKEN* tk) { + if(tk->type == keyword) + if(existsinarray(&vartypes, tk->token)) + return true; + return false; +} + +char* parsetype(PARSER* p) { + if(p->current->type != identifier); + unexpected(p); + + char* result = p->current->token; + next(p); + return result; +} + +void parsevardeccommon(PARSER* p, VARDEC* v) { + v->typeclass = p->current->type; + v->primitive = isprimitive(p->current); + v->type = parsetype(p); + + STRINGLIST* currstr = (STRINGLIST*)malloc(sizeof(STRINGLIST)); + v->names = currstr; + + v->debug = getdebug(p); + + v->names->content = parseidentifier(p); + + while(!strcmp(p->current->token, ",")) { + next(p); + STRINGLIST* nextstr = (STRINGLIST*)malloc(sizeof(STRINGLIST)); + nextstr->content = parseidentifier(p); + currstr->next = nextstr; + currstr = nextstr; + } + currstr->next = NULL; + + checkcontent(p, ";"); +} + + +VARDEC* parsevardec(PARSER* p) { + if(strcmp(p->current->token, "var")) + return NULL; + next(p); + + VARDEC* vardec = (VARDEC*)malloc(sizeof(VARDEC)); + + parsevardeccommon(p, vardec); + + return vardec; +} + +VARDEC* parsevardecs(PARSER* p) { + VARDEC* head = parsevardec(p); + VARDEC* curr = head; + VARDEC* next; + while(next = parsevardec(p), next != NULL) { + curr->next = next; + curr = next; + } + if(curr != NULL) + curr->next = NULL; + return head; +} diff --git a/parser-structure.h b/parser-structure.h new file mode 100644 index 0000000..8c1cf34 --- /dev/null +++ b/parser-structure.h @@ -0,0 +1,5 @@ +#ifndef PARSER_STRUCTURE_H +#define PARSER_STRUCTURE_H +#include "parser.h" +CLASS* parseclasses(PARSER* p); +#endif diff --git a/parser.c b/parser.c index 0387d4a..3d90ed7 100644 --- a/parser.c +++ b/parser.c @@ -3,527 +3,9 @@ #include #include #include "parser.h" -#include "parser-constants.h" - -char* parseidentifier(PARSER* p); -STATEMENT* parsestatements(PARSER* p); -SUBROUTCALL* parsesubroutcall(PARSER* p); -TERM* parseexpression(PARSER* p); -TERM* parseterm(PARSER* p); - -DEBUGINFO* getdebug(PARSER* p) { - DEBUGINFO* d = (DEBUGINFO*)malloc(sizeof(DEBUGINFO)); - d->file = p->file; - d->definedat = p->current->definedat; - return d; -} - -void next(PARSER* p) { - p->current = p->current->next; -} - -void checkpoint(PARSER* p) { - p->checkpoint = p->current; -} - -void restorecp(PARSER* p) { - p->current = p->checkpoint; -} - -void unexpectedtoken(PARSER* p) { - fprintf(stderr, "Unexpected token '%s' (of type %s); line %i, file '%s'\n", p->current->token, tokentypes.items[p->current->type], p->current->definedat, p->file); -} - -void unexpected(PARSER* p) { - unexpectedtoken(p); - exit(1); -} - -void checkcontent(PARSER* p, const char* content) { - if(strcmp(p->current->token, content)) - unexpected(p); - next(p); -} - -void checktype(PARSER* p, TOKENTYPE type) { - if(p->current->type != type) { - fprintf(stderr, "Unexpected %s; line %i, file '%s'\n", tokentypes.items[p->current->type], p->current->definedat, p->file); - exit(1); - } -} - -TERM* parsetermnullified(PARSER* p) { - TERM* t = (TERM*)malloc(sizeof(TERM)); - - if(p->current->type == integer) { - t->type = intconstant; - t->integer = atoi(p->current->token); - next(p); - } else if(p->current->type == string) { - t->type = stringconstant; - t->string = p->current->token; - next(p); - } else if(p->current->type == keyword) { - t->type = keywordconstant; - bool valid = false; - for(int i = 0; i < keywordconstants.size; i++) - if(!strcmp(p->current->token, keywordconstants.items[i])) - valid = true; - if(!valid) - unexpected(p); - - t->string = p->current->token; - next(p); - } else if(!strcmp(p->current->token, "-") || !strcmp(p->current->token, "~")) { - t->type = unaryopterm; - next(p); - t->expression = parseterm(p); - t->expression->next = NULL; - } else if(!strcmp(p->current->token, "(")) { - next(p); - t->type = innerexpression; - t->expression = parseexpression(p); - checkcontent(p, ")"); - } else if(p->current->type == identifier) { - SUBROUTCALL* call = parsesubroutcall(p); - if(call == NULL) { - t->string = p->current->token; - next(p); - if(!strcmp(p->current->token, "[")) { - next(p); - t->arrayexp = parseexpression(p); - t->type = arrayitem; - checkcontent(p, "]"); - } else { - t->type = varname; - } - } else { - t->type = subroutcall; - t->call = call; - } - } else { - return NULL; - } - return t; -} - -bool isop(TOKEN* t) { - for(int i = 0; i < operators.size; i++) - if(!strcmp(t->token, operators.items[i])) - return true; - return false; -} - -TERM* parseexpressionnullified(PARSER* p) { - TERM* head = parseterm(p); - TERM* current = head; - TERM* nextt; - while(isop(p->current)) { - current->op = p->current->token[0]; - next(p); - nextt = parseterm(p); - current->next = nextt; - current = nextt; - } - if(current != NULL) - current->next = NULL; - return head; -} - -TERM* parseterm(PARSER* p) { - TERM* t = parsetermnullified(p); - if(t == NULL) - unexpected(p); - return t; -} - -TERM* parseexpression(PARSER* p) { - TERM* t = parseexpressionnullified(p); - if(t == NULL) - unexpected(p); - return t; -} - -EXPRESSIONLIST* parseexpressionlist(PARSER* p) { - if(!strcmp(p->current->token, ")")) - return NULL; - EXPRESSIONLIST* head = (EXPRESSIONLIST*)malloc(sizeof(EXPRESSIONLIST)); - head->expression = parseexpressionnullified(p); - EXPRESSIONLIST* current = head; - EXPRESSIONLIST* nextls; - while(!strcmp(p->current->token, ",")) { - next(p); - nextls = (EXPRESSIONLIST*)malloc(sizeof(EXPRESSIONLIST)); - nextls->expression = parseexpression(p); - current->next = nextls; - current = nextls; - } - if(current != NULL) - current->next = NULL; - return head; -} - -SUBROUTCALL* parsesubroutcall(PARSER* p) { - checkpoint(p); - SUBROUTCALL* call = (SUBROUTCALL*)malloc(sizeof(SUBROUTCALL)); - if(!strcmp(p->current->next->token, ".")) { - if(p->current->type != identifier) { - free(call); - return NULL; - } - call->parentname = p->current->token; - next(p); - next(p); - } - else - call->parentname = NULL; - - if(p->current->type != identifier) { - free(call); - restorecp(p); - return NULL; - } - call->debug = getdebug(p); - - call->name = p->current->token; - next(p); - - if(strcmp(p->current->token, "(")) { - free(call); - restorecp(p); - return NULL; - } - next(p); - - call->parameters = parseexpressionlist(p); - - if(strcmp(p->current->token, ")")) { - free(call); - restorecp(p); - return NULL; - } - next(p); - return call; -} - -CONDSTATEMENT* parsecond(PARSER* p) { - checkcontent(p, "("); - CONDSTATEMENT* st = (CONDSTATEMENT*)malloc(sizeof(CONDSTATEMENT)); - st->expression = parseexpression(p); - checkcontent(p, ")"); - checkcontent(p, "{"); - st->statements = parsestatements(p); - checkcontent(p, "}"); - - return st; -} - -IFSTATEMENT* parseif(PARSER* p) { - IFSTATEMENT* ifst = (IFSTATEMENT*)malloc(sizeof(IFSTATEMENT)); - - ifst->base = parsecond(p); - - if(!strcmp(p->current->token, "else")) { - next(p); - checkcontent(p, "{"); - ifst->elsestatements = parsestatements(p); - checkcontent(p, "}"); - } - else - ifst->elsestatements = NULL; - - return ifst; -} - -LETSTATEMENT* parselet(PARSER* p) { - LETSTATEMENT* letstatement = (LETSTATEMENT*)malloc(sizeof(LETSTATEMENT)); - - letstatement->varname = parseidentifier(p); - - if(!strcmp(p->current->token, "[")) { - next(p); - letstatement->arrayind = parseexpression(p); - checkcontent(p, "]"); - } - else - letstatement->arrayind = NULL; - - checkcontent(p, "="); - - letstatement->expression = parseexpression(p); - - checkcontent(p, ";"); - - return letstatement; -} - -STATEMENT* parsestatement(PARSER* p) { - STATEMENT* st = (STATEMENT*)malloc(sizeof(STATEMENT)); - if(!strcmp(p->current->token, "let")) { - next(p); - st->type = letstatement; - st->letstatement = parselet(p); - } else if(!strcmp(p->current->token, "if")) { - next(p); - st->type = ifstatement; - st->ifstatement = parseif(p); - } else if(!strcmp(p->current->token, "while")) { - next(p); - st->type = whilestatement; - st->whilestatement = parsecond(p); - } else if(!strcmp(p->current->token, "do")) { - next(p); - st->type = dostatement; - st->dostatement = parsesubroutcall(p); - checkcontent(p, ";"); - } else if(!strcmp(p->current->token, "return")) { - next(p); - st->type = returnstatement; - if(strcmp(p->current->token, ";")) { - st->retstatement = parseexpressionnullified(p); - checkcontent(p, ";"); - } - else { - st->retstatement = NULL; - next(p); - } - } else { - free(st); - return NULL; - } - return st; -} - -STATEMENT* parsestatements(PARSER* p) { - STATEMENT* head = parsestatement(p); - STATEMENT* current = head; - STATEMENT* next; - while(next = parsestatement(p), next != NULL) { - current->next = next; - current = next; - } - if(current != NULL) - current->next = NULL; - return head; -} - -char* parsetype(PARSER* p, bool* primitive) { - char* result = p->current->token; - if(p->current->type == keyword) - for(int i = 0; i < vartypes.size; i++) { - if(!strcmp(p->current->token, vartypes.items[i])) { - next(p); - *primitive = true; - return result; - } - } - else if (p->current->type == identifier) { - next(p); - *primitive = false; - return result; - } - else - unexpected(p); -} - -int parsepossibilities(PARSER* p, STRINGARRAY* poss) { - for(int i = 0; i < poss->size; i++) - if(!strcmp(p->current->token, poss->items[i])) - return i; - return -1; -} - -CLASSVARTYPE parseclassvartype(PARSER* p) { - return parsepossibilities(p, &classvartypes); -} - -SUBROUTCLASS parsesubroutclass(PARSER* p) { - return parsepossibilities(p, &subroutclasses); -} - -char* parseidentifier(PARSER* p) { - checktype(p, identifier); - char* result = p->current->token; - next(p); - return result; -} - -void parsevardeccommon(PARSER* p, VARDEC* v) { - v->typeclass = p->current->type; - v->type = parsetype(p, &(v->primitive)); - - STRINGLIST* currstr = (STRINGLIST*)malloc(sizeof(STRINGLIST)); - v->names = currstr; - - v->debug = getdebug(p); - - v->names->content = parseidentifier(p); - - while(!strcmp(p->current->token, ",")) { - next(p); - STRINGLIST* nextstr = (STRINGLIST*)malloc(sizeof(STRINGLIST)); - nextstr->content = parseidentifier(p); - currstr->next = nextstr; - currstr = nextstr; - } - currstr->next = NULL; - - checkcontent(p, ";"); -} - -CLASSVARDEC* parseclassvardec(PARSER* p) { - CLASSVARTYPE classvartype = parseclassvartype(p); - if(classvartype == -1) - return NULL; - next(p); - - CLASSVARDEC* classvardec = (CLASSVARDEC*)malloc(sizeof(CLASSVARDEC)); - classvardec->type = classvartype; - - classvardec->base = (VARDEC*)malloc(sizeof(VARDEC)); - - parsevardeccommon(p, classvardec->base); - - return classvardec; -} - -CLASSVARDEC* parseclassvardecs(PARSER* p) { - CLASSVARDEC* head = parseclassvardec(p); - CLASSVARDEC* current = head; - CLASSVARDEC* next; - while(next = parseclassvardec(p), next != NULL) { - current->next = next; - current= next; - } - if(current != NULL) - current->next = NULL; - return head; -} - -VARDEC* parsevardec(PARSER* p) { - if(strcmp(p->current->token, "var")) - return NULL; - next(p); - - VARDEC* vardec = (VARDEC*)malloc(sizeof(VARDEC)); - - parsevardeccommon(p, vardec); - - return vardec; -} - -VARDEC* parsevardecs(PARSER* p) { - VARDEC* head = parsevardec(p); - VARDEC* current = head; - VARDEC* next; - while(next = parsevardec(p), next != NULL) { - current->next = next; - current = next; - } - if(current != NULL) - current->next = NULL; - return head; -} - -PARAMETER* parseparameter(PARSER* p) { - PARAMETER* param = (PARAMETER*)malloc(sizeof(PARAMETER)); - if(!strcmp(p->current->token, ")")) - return NULL; - bool dummy; - param->type = parsetype(p, &dummy); - param->name = parseidentifier(p); - return param; -} - -PARAMETER* parseparameters(PARSER* p) { - PARAMETER* head = parseparameter(p); - PARAMETER* current = head; - while(!strcmp(p->current->token, ",")) { - next(p); - current->next = parseparameter(p); - current = current->next; - } - if(current != NULL) - current->next = NULL; - return head; -} - -SUBROUTBODY* parsesubroutbody(PARSER* p) { - SUBROUTBODY* subroutbody = (SUBROUTBODY*)malloc(sizeof(SUBROUTBODY)); - subroutbody->vardecs = parsevardecs(p); - subroutbody->statements = parsestatements(p); - - return subroutbody; -} - -SUBROUTDEC* parsesubroutdec(PARSER* p) { - SUBROUTCLASS subroutclass = parsesubroutclass(p); - if(subroutclass == -1) - return NULL; - - next(p); - SUBROUTDEC* subroutdec = (SUBROUTDEC*)malloc(sizeof(SUBROUTDEC)); - subroutdec->subroutclass = subroutclass; - - subroutdec->typeclass = p->current->type; - if(!strcmp(p->current->token, "void")) { - subroutdec->type = p->current->token; - next(p); - } - else { - bool dummy; - subroutdec->type = parsetype(p, &dummy); - } - - subroutdec->debug = getdebug(p); - - subroutdec->name = parseidentifier(p); - - checkcontent(p, "("); - subroutdec->parameters = parseparameters(p); - checkcontent(p, ")"); - - checkcontent(p, "{"); - subroutdec->body = parsesubroutbody(p); - checkcontent(p, "}"); - - return subroutdec; -} - -SUBROUTDEC* parsesubroutdecs(PARSER* p) { - SUBROUTDEC* head = parsesubroutdec(p); - SUBROUTDEC* current = head; - SUBROUTDEC* next; - while(next = parsesubroutdec(p), next != NULL) { - current->next = next; - current = next; - } - if(current != NULL) - current->next = NULL; - return head; -} - -CLASS* parseclass(PARSER* p) { - checkcontent(p, "class"); - - CLASS* class = (CLASS*)malloc(sizeof(CLASS)); - - class->debug = getdebug(p); - - class->name = parseidentifier(p); - - checkcontent(p, "{"); - - class->vardecs = parseclassvardecs(p); - - class->subroutdecs = parsesubroutdecs(p); - - checkcontent(p, "}"); - - class->next = NULL; - return class; -} +#include "parser-structure.h" +// Statements PARSER* mkparser(TOKEN* tokens, char* file) { PARSER* parser = (PARSER*)malloc(sizeof(PARSER)); parser->tokens = tokens; @@ -533,5 +15,5 @@ PARSER* mkparser(TOKEN* tokens, char* file) { } void parse(PARSER* parser) { - parser->output = parseclass(parser); + parser->output = parseclasses(parser); } diff --git a/parser.h b/parser.h index bb02a8c..a8ad6c2 100644 --- a/parser.h +++ b/parser.h @@ -1,6 +1,5 @@ #ifndef PARSER_H #define PARSER_H -#include #include "tokenizer.h" #include "parser-tree.h" diff --git a/tokenizer.c b/tokenizer.c index 3838b4b..62e1d1b 100644 --- a/tokenizer.c +++ b/tokenizer.c @@ -238,7 +238,6 @@ TOKEN* tokenize(FILE* input) { if(curtype == charsymbol) append(tmptoken, c); } - lasttype = curtype; } diff --git a/util.c b/util.c index 6d45bc8..35a4f46 100644 --- a/util.c +++ b/util.c @@ -66,3 +66,10 @@ void freestrlist(STRINGLIST* strlist) { if(next != NULL) freestrlist(next); } + +bool existsinarray(STRINGARRAY* arr, const char* item) { + for(int i = 0; i < arr->size; i++) + if(!strcmp(arr->items[i], item)) + return true; + return false; +} diff --git a/util.h b/util.h index 131e81c..248c206 100644 --- a/util.h +++ b/util.h @@ -1,6 +1,7 @@ #ifndef UTIL_H #define UTIL_H #include +#include /* util * Random utilities. */ @@ -29,4 +30,6 @@ void* copy(void* v, int size); STRINGLIST* initstrlist(const char** strs, int count); void printstrlist(STRINGLIST* strlist, FILE* stream); void freestrlist(STRINGLIST* strlist); + +bool existsinarray(STRINGARRAY* arr, const char* item); #endif