diff --git a/parser/parser.c b/parser/parser.c index 56dee5c..d6d67a1 100644 --- a/parser/parser.c +++ b/parser/parser.c @@ -20,6 +20,7 @@ enum SYNTAX_ERROR op_rel(struct Parser *parser) { } enum SYNTAX_ERROR fator(struct Parser *parser) { + // this makes no damn sense: keeping it for unit tests, I guess if (!(parser->token.category == ID || parser->token.category == INTCON || parser->token.category == REALCON || parser->token.category == CHARCON || @@ -84,11 +85,6 @@ enum SYNTAX_ERROR arrayFator(struct Parser *parser) { return NO_ERROR; } -enum SYNTAX_ERROR expr(struct Parser *parser) { - // TODO: - return NO_ERROR; -} - /** * prog accepts repetitions of declarations of variables (decl_list_var), or * procedures (decl_list_proc). @@ -137,8 +133,8 @@ enum SYNTAX_ERROR declListVar(struct Parser *parser) { if (error != NO_ERROR) { return error; } - // TODO: handle multiple variable declarations here - parser->token = lexerGetNextChar(parser->fd, parser->lineCount); + // handle multiple variable declarations here + // parser->token = lexerGetNextChar(parser->fd, parser->lineCount); while (parser->token.category == SIGN && parser->token.signCode == COMMA) { parser->token = lexerGetNextChar(parser->fd, parser->lineCount); enum SYNTAX_ERROR error = declVar(parser); @@ -149,6 +145,7 @@ enum SYNTAX_ERROR declListVar(struct Parser *parser) { return NO_ERROR; } +// HACK: This looks BAD !!! enum SYNTAX_ERROR declVar(struct Parser *parser) { if (parser->token.category != ID) { return NO_VAR_ID; @@ -156,6 +153,7 @@ enum SYNTAX_ERROR declVar(struct Parser *parser) { parser->token = lexerGetNextChar(parser->fd, parser->lineCount); bool isArray = false; + bool isAssignment = false; int arrayDimensions = 0; // is array if (parser->token.category == SIGN && parser->token.signCode == OPEN_BRACK) { @@ -184,6 +182,7 @@ enum SYNTAX_ERROR declVar(struct Parser *parser) { // assignment if (parser->token.category == SIGN && parser->token.signCode == ASSIGN) { + isAssignment = true; if (isArray) { parser->token = lexerGetNextChar(parser->fd, parser->lineCount); if (!(parser->token.category == SIGN && @@ -224,6 +223,10 @@ enum SYNTAX_ERROR declVar(struct Parser *parser) { } } + if (isArray || isAssignment) { + parser->token = lexerGetNextChar(parser->fd, parser->lineCount); + } + return NO_ERROR; } @@ -234,9 +237,11 @@ enum SYNTAX_ERROR declDefProc(struct Parser *parser) { } parser->token = lexerGetNextChar(parser->fd, parser->lineCount); + // is def if (isDef) { - if (!(parser->token.category == ID || parser->token.signCode == INIT)) { - return NO_DEF_ID; + enum SYNTAX_ERROR error = declDef(parser); + if (error != NO_ERROR) { + return error; } // is prot } else { @@ -249,6 +254,303 @@ enum SYNTAX_ERROR declDefProc(struct Parser *parser) { return NO_ERROR; } +enum SYNTAX_ERROR declDef(struct Parser *parser) { + if (!(parser->token.category == ID || parser->token.signCode == INIT)) { + return NO_DEF_ID; + } + + parser->token = lexerGetNextChar(parser->fd, parser->lineCount); + if (!(parser->token.category == SIGN && parser->token.signCode == OPEN_PAR)) { + return INVALID_DEF_PAREN_OPEN; + } + + // valid param loop + parser->token = lexerGetNextChar(parser->fd, parser->lineCount); + enum SYNTAX_ERROR error = declDefParam(parser); + if (error != NO_ERROR) { + return error; + } + + // can be endp, declListVar, or cmd + parser->token = lexerGetNextChar(parser->fd, parser->lineCount); + if (!(parser->token.category == ID || + (parser->token.category == RSV && + (parser->token.signCode == CONST || parser->token.signCode == INT || + parser->token.signCode == CHAR || parser->token.signCode == REAL || + parser->token.signCode == BOOL || parser->token.signCode == WHILE || + parser->token.signCode == VAR || parser->token.signCode == IF || + parser->token.signCode == GETOUT || + parser->token.signCode == GETINT || + parser->token.signCode == GETREAL || + parser->token.signCode == GETCHAR || + parser->token.signCode == GETSTR || + parser->token.signCode == PUTINT || + parser->token.signCode == PUTREAL || + parser->token.signCode == PUTCHAR || + parser->token.signCode == PUTSTR || parser->token.signCode == ENDP || + parser->token.signCode == DO)))) { + return NO_DEF_VALID_TOKEN_AFTER_PAREN; + } + + // is decl_list_var + if (parser->token.signCode == CONST || parser->token.signCode == CHAR || + parser->token.signCode == INT || parser->token.signCode == REAL || + parser->token.signCode == BOOL) { + enum SYNTAX_ERROR error = declListVar(parser); + if (error != NO_ERROR) { + return error; + } + } + + // is cmd + if (parser->token.category == RSV && + (parser->token.signCode == DO || parser->token.signCode == WHILE || + parser->token.signCode == VAR || parser->token.signCode == IF || + parser->token.signCode == GETOUT || + parser->token.signCode == GETINT || + parser->token.signCode == GETREAL || + parser->token.signCode == GETCHAR || + parser->token.signCode == GETSTR || + parser->token.signCode == PUTINT || + parser->token.signCode == PUTREAL || + parser->token.signCode == PUTCHAR || + parser->token.signCode == PUTSTR) || + parser->token.category == ID) { + enum SYNTAX_ERROR error = cmd(parser); + if (error != NO_ERROR) { + return error; + } + } + + // is endp + if (!(parser->token.category == RSV && parser->token.signCode == ENDP)) { + return NO_DEF_END_KEYWORD; + } + + return NO_ERROR; +} + +enum SYNTAX_ERROR cmd(struct Parser *parser) { + if (parser->token.signCode == GETINT) { + parser->token = lexerGetNextChar(parser->fd, parser->lineCount); + if (!(parser->token.category == ID)) { + return NO_GETINT_ID; + } + parser->token = lexerGetNextChar(parser->fd, parser->lineCount); + } + + if (parser->token.signCode == GETREAL) { + parser->token = lexerGetNextChar(parser->fd, parser->lineCount); + if (!(parser->token.category == ID)) { + return NO_GETREAL_ID; + } + parser->token = lexerGetNextChar(parser->fd, parser->lineCount); + } + + if (parser->token.signCode == GETCHAR) { + parser->token = lexerGetNextChar(parser->fd, parser->lineCount); + if (!(parser->token.category == ID)) { + return NO_GETCHAR_ID; + } + parser->token = lexerGetNextChar(parser->fd, parser->lineCount); + } + + if (parser->token.signCode == GETSTR) { + parser->token = lexerGetNextChar(parser->fd, parser->lineCount); + if (!(parser->token.category == ID)) { + return NO_GETSTR_ID; + } + parser->token = lexerGetNextChar(parser->fd, parser->lineCount); + } + + if (parser->token.signCode == PUTINT) { + parser->token = lexerGetNextChar(parser->fd, parser->lineCount); + if (!(parser->token.category == ID || parser->token.category == INTCON)) { + return INVALID_PUTINT_ELEMENT; + } + parser->token = lexerGetNextChar(parser->fd, parser->lineCount); + } + + if (parser->token.signCode == PUTREAL) { + parser->token = lexerGetNextChar(parser->fd, parser->lineCount); + if (!(parser->token.category == ID || parser->token.category == REALCON)) { + return INVALID_PUTREAL_ELEMENT; + } + parser->token = lexerGetNextChar(parser->fd, parser->lineCount); + } + + if (parser->token.signCode == PUTCHAR) { + parser->token = lexerGetNextChar(parser->fd, parser->lineCount); + if (!(parser->token.category == ID || parser->token.category == CHARCON)) { + return INVALID_PUTCHAR_ELEMENT; + } + parser->token = lexerGetNextChar(parser->fd, parser->lineCount); + } + + if (parser->token.signCode == PUTSTR) { + parser->token = lexerGetNextChar(parser->fd, parser->lineCount); + if (!(parser->token.category == ID || + parser->token.category == STRINGCON)) { + return INVALID_PUTSTR_ELEMENT; + } + parser->token = lexerGetNextChar(parser->fd, parser->lineCount); + } + + if (parser->token.signCode == DO) { + enum SYNTAX_ERROR error = cmdDo(parser); + if (error != NO_ERROR) { + return error; + } + } + + if (parser->token.category == ID) { + enum SYNTAX_ERROR error = cmdAtrib(parser); + if (error != NO_ERROR) { + return error; + } + } + + // getout: nothing needed? + + return NO_ERROR; +} + +enum SYNTAX_ERROR cmdAtrib(struct Parser *parser) { + parser->token = lexerGetNextChar(parser->fd, parser->lineCount); + if (!(parser->token.category == SIGN && + (parser->token.signCode == OPEN_BRACK || + parser->token.signCode == ASSIGN))) { + return NO_ATRIB_VALID_TOKEN_AFTER_ID; + } + + if (parser->token.category == SIGN && parser->token.signCode == ASSIGN) { + enum SYNTAX_ERROR error = fator(parser); + if (error != NO_ERROR) { + return error; + } + } + + // arrayAtrib + while (parser->token.category == SIGN && + parser->token.signCode == OPEN_BRACK) { + parser->token = lexerGetNextChar(parser->fd, parser->lineCount); + enum SYNTAX_ERROR error = expr(parser); + if (error != NO_ERROR) { + return error; + } + } + + return NO_ERROR; +} + +enum SYNTAX_ERROR cmdDo(struct Parser *parser) { + parser->token = lexerGetNextChar(parser->fd, parser->lineCount); + if (!(parser->token.category == ID)) { + return INVALID_FUNCTION_CALL_ID; + } + + // is id, ok... then it should open a paren + parser->token = lexerGetNextChar(parser->fd, parser->lineCount); + if (!(parser->token.category == SIGN && parser->token.signCode == OPEN_PAR)) { + return INVALID_FUNCTION_CALL_PAREN_OPEN; + } + + // if is valid fator starter, go to fator + if (parser->token.category == ID || parser->token.category == INTCON || + parser->token.category == REALCON || parser->token.category == CHARCON || + (parser->token.category == SIGN && parser->token.signCode == OPEN_PAR) || + (parser->token.category == SIGN && parser->token.signCode == NEGATION)) { + // goes from expr down to fator + enum SYNTAX_ERROR error = expr(parser); + if (error != NO_ERROR) { + return error; + } + } + + parser->token = lexerGetNextChar(parser->fd, parser->lineCount); + if (!(parser->token.category == SIGN && parser->token.signCode == CLOSE_PAR)) { + return INVALID_FUNCTION_CALL_PAREN_CLOSE; + } + + return NO_ERROR; +} + +enum SYNTAX_ERROR expr(struct Parser *parser) { + // TODO: + return NO_ERROR; +} + +enum SYNTAX_ERROR declDefParam(struct Parser *parser) { + // while it's a param, delimited by comma + do { + // skip the comma if it's a subsequent param + if (parser->token.category == SIGN && parser->token.signCode == COMMA) { + parser->token = lexerGetNextChar(parser->fd, parser->lineCount); + } + + // & is optional + if (parser->token.category == SIGN && parser->token.signCode == REF) { + parser->token = lexerGetNextChar(parser->fd, parser->lineCount); + } + + // type is valid + if (!(parser->token.category == RSV && + (parser->token.signCode == INT || parser->token.signCode == CHAR || + parser->token.signCode == REAL || parser->token.signCode == BOOL))) { + return INVALID_DEF_PARAM_TYPE; + } + + // param id + parser->token = lexerGetNextChar(parser->fd, parser->lineCount); + if (!(parser->token.category == ID)) { + return NO_DEF_PARAM_ID; + } + + // valid token after id + parser->token = lexerGetNextChar(parser->fd, parser->lineCount); + if (!(parser->token.category == SIGN && + (parser->token.signCode == OPEN_BRACK || + parser->token.signCode == COMMA || + parser->token.signCode == CLOSE_PAR))) { + return NO_DEF_VALID_TOKEN_AFTER_ID; + } + // CLOSE_PAR has no extra steps: simply breaks the loop and leaves + + // OPEN_BRACK defines an array param + if (parser->token.signCode == OPEN_BRACK) { + enum SYNTAX_ERROR error = declDefParamArray(parser); + if (error != NO_ERROR) { + return error; + } + } + + // COMMA loops the whole thing + } while (parser->token.category == SIGN && parser->token.signCode == COMMA); + + return NO_ERROR; +} + +enum SYNTAX_ERROR declDefParamArray(struct Parser *parser) { + do { + parser->token = lexerGetNextChar(parser->fd, parser->lineCount); + if (!(parser->token.category == ID || parser->token.category == INTCON)) { + return INVALID_ARRAY_DEF_PARAM_SUBSCRIPT_TYPE; + } + + parser->token = lexerGetNextChar(parser->fd, parser->lineCount); + if (!(parser->token.category == SIGN && + parser->token.signCode == CLOSE_BRACK)) { + return INVALID_ARRAY_DEF_PARAM_BRACKET_CLOSE; + } + + // consume next (should be OPEN_BRACK or COMMA) + parser->token = lexerGetNextChar(parser->fd, parser->lineCount); + } while (parser->token.signCode == OPEN_BRACK); + + // is COMMA + return NO_ERROR; +} + enum SYNTAX_ERROR declProt(struct Parser *parser) { if (!(parser->token.category == ID)) { return NO_PROTO_ID; @@ -275,7 +577,6 @@ enum SYNTAX_ERROR declProt(struct Parser *parser) { } enum SYNTAX_ERROR declProtParam(struct Parser *parser) { - if (parser->token.category == SIGN && parser->token.signCode == REF) { parser->token = lexerGetNextChar(parser->fd, parser->lineCount); } @@ -323,13 +624,13 @@ enum SYNTAX_ERROR declProtParam(struct Parser *parser) { return INVALID_ARRAY_DIMENSION_DECLARATION; } } + } - if (parser->token.category == SIGN && parser->token.signCode == COMMA) { - parser->token = lexerGetNextChar(parser->fd, parser->lineCount); - enum SYNTAX_ERROR error = declProtParam(parser); - if (error != NO_ERROR) { - return error; - } + if (parser->token.category == SIGN && parser->token.signCode == COMMA) { + parser->token = lexerGetNextChar(parser->fd, parser->lineCount); + enum SYNTAX_ERROR error = declProtParam(parser); + if (error != NO_ERROR) { + return error; } } return NO_ERROR; diff --git a/parser/parser.h b/parser/parser.h index 224294b..494130b 100644 --- a/parser/parser.h +++ b/parser/parser.h @@ -7,7 +7,7 @@ struct Parser { struct Token token; - FILE* fd; + FILE *fd; int *lineCount; }; @@ -34,4 +34,14 @@ enum SYNTAX_ERROR declProtParam(struct Parser *parser); /*void arrayDeclaration(FILE *fd, int *lineCount, struct Token token);*/ /*void arrayInitialization(FILE *fd, int *lineCount, struct Token token);*/ +enum SYNTAX_ERROR declDef(struct Parser *parser); +enum SYNTAX_ERROR declDefParam(struct Parser *parser); +enum SYNTAX_ERROR declDefParamArray(struct Parser *parser); + +enum SYNTAX_ERROR cmd(struct Parser *parser); +enum SYNTAX_ERROR getint(struct Parser *parser); + +enum SYNTAX_ERROR cmdDo(struct Parser *parser); +enum SYNTAX_ERROR cmdAtrib(struct Parser *parser); + #endif diff --git a/parser/syntax_error.c b/parser/syntax_error.c index d089a6a..02a85d7 100644 --- a/parser/syntax_error.c +++ b/parser/syntax_error.c @@ -2,7 +2,7 @@ #include #include -#define ERROR_QTY 84 +#define ERROR_QTY 91 // ANSI escape codes #define RESET "\033[0m" @@ -46,9 +46,9 @@ void printSyntaxError(enum SYNTAX_ERROR error, int *lineCount) { {INVALID_PROTO_PAREN_CLOSE, "No closing paren in function prototype"}, {INVALID_PROTO_PARAM_TYPE, "Invalid parameter type for function prototype"}, - {NO_PROTO_VALID_TOKEN_AFTER_TYPE, - "No valid token found after function prototype type, expected bracket open " - "or comma"}, + {NO_PROTO_VALID_TOKEN_AFTER_TYPE, "No valid token found after function " + "prototype type, expected bracket open " + "or comma"}, {INVALID_ARRAY_PROTO_PARAM_BRACKET_OPEN, "No opening bracket for function prototype array parameter"}, {INVALID_ARRAY_PROTO_PARAM_BRACKET_CLOSE, @@ -59,8 +59,12 @@ void printSyntaxError(enum SYNTAX_ERROR error, int *lineCount) { "Expected valid token after bracket closing: bracket opening, comma or " "paren close"}, {NO_DEF_ID, "No valid ID for function definition"}, + {INVALID_DEF_PAREN_OPEN, "No valid paren open for function definition"}, + {INVALID_DEF_PAREN_CLOSE, "No valid paren close for function definition"}, {INVALID_DEF_PARAM_TYPE, "No valid parameter type for function definition"}, + {NO_DEF_VALID_TOKEN_AFTER_ID, "No valid token after def id, expected " + "open bracket, comma or paren close"}, {NO_DEF_PARAM_ID, "No ID detected for function definition parameter"}, {INVALID_ARRAY_DEF_PARAM_SUBSCRIPT_TYPE, "No valid type for subscript in array parameter of function " @@ -72,6 +76,9 @@ void printSyntaxError(enum SYNTAX_ERROR error, int *lineCount) { {INVALID_DEF_PARAM_LIST, "Invalid parameter list for function definition"}, {NO_DEF_END_KEYWORD, "End keyword for function definition not detected"}, + {NO_DEF_VALID_TOKEN_AFTER_PAREN, + "No valid token after def paren close, expected endp, variable " + "declaration, or cmd"}, {NO_FUNCTION_END_PAREN_CLOSE, "No paren close for function end"}, // cmd {INVALID_CMD_CONTENT, "Invalid command keyword or content"}, @@ -122,6 +129,9 @@ void printSyntaxError(enum SYNTAX_ERROR error, int *lineCount) { {NO_ATRIB_ID, "No ID detected for expression assign"}, {NO_ATRIB_ASSIGN, "No assign symbol for expression assign"}, {NO_ATRIB_EXPR, "No expression assigned to expression assign"}, + {NO_ATRIB_VALID_TOKEN_AFTER_ID, + "No valid token after identifier for assignment"}, + {NO_ATRIB_BRACKET_CLOSE, "Expected bracket closing at array assignment"}, // expr {NO_EXPR_EXPR_SIMP, "No simple expression for expression"}, {NO_EXPR_EXPR_SIMP_AFTER_OP_REL, "No simple expression after operation"}, @@ -140,6 +150,7 @@ void printSyntaxError(enum SYNTAX_ERROR error, int *lineCount) { "No factor detected after valid sign in term"}, // fator {NO_FACTOR_VALID_START_SYMBOL, "No factor valid start symbol"}, + {NO_FACTOR_VALID_SYMBOL_AFTER_ID, "No factor valid symbol after id"}, {INVALID_FACTOR_ARRAY_BRACKET_OPEN, "No factor array bracket opening"}, {INVALID_FACTOR_ARRAY_BRACKET_CLOSE, "No factor array bracket closing"}, {INVALID_FACTOR_EXPR_PAREN_OPEN, "No factor expression paren opening"}, diff --git a/parser/syntax_error.h b/parser/syntax_error.h index 7d662b5..782bd58 100644 --- a/parser/syntax_error.h +++ b/parser/syntax_error.h @@ -38,13 +38,17 @@ enum SYNTAX_ERROR { INVALID_PROTO_PARAM_LIST, NO_PROTO_VALID_TOKEN_AFTER_BRACKET_CLOSE, NO_DEF_ID, + INVALID_DEF_PAREN_OPEN, + INVALID_DEF_PAREN_CLOSE, INVALID_DEF_PARAM_TYPE, + NO_DEF_VALID_TOKEN_AFTER_ID, NO_DEF_PARAM_ID, INVALID_ARRAY_DEF_PARAM_SUBSCRIPT_TYPE, INVALID_ARRAY_DEF_PARAM_BRACKET_OPEN, INVALID_ARRAY_DEF_PARAM_BRACKET_CLOSE, INVALID_DEF_PARAM_LIST, NO_DEF_END_KEYWORD, + NO_DEF_VALID_TOKEN_AFTER_PAREN, NO_FUNCTION_END_PAREN_CLOSE, // cmd INVALID_CMD_CONTENT, @@ -91,6 +95,8 @@ enum SYNTAX_ERROR { NO_ATRIB_ID, NO_ATRIB_ASSIGN, NO_ATRIB_EXPR, + NO_ATRIB_VALID_TOKEN_AFTER_ID, + NO_ATRIB_BRACKET_CLOSE, // expr NO_EXPR_EXPR_SIMP, NO_EXPR_EXPR_SIMP_AFTER_OP_REL, @@ -105,6 +111,7 @@ enum SYNTAX_ERROR { NO_TERM_FACTOR_AFTER_FACTOR_VALID_SIGN, // fator NO_FACTOR_VALID_START_SYMBOL, + NO_FACTOR_VALID_SYMBOL_AFTER_ID, INVALID_FACTOR_ARRAY_BRACKET_OPEN, INVALID_FACTOR_ARRAY_BRACKET_CLOSE, INVALID_FACTOR_EXPR_PAREN_OPEN, @@ -118,7 +125,7 @@ void printSyntaxError(enum SYNTAX_ERROR error, int *lineCount); struct ErrorMessage { enum SYNTAX_ERROR error; - const char* message; + const char *message; }; #endif // !SYNTAX_ERROR_H diff --git a/test/parser_integration_tests.c b/test/parser_integration_tests.c index 4b55e15..99e25c4 100644 --- a/test/parser_integration_tests.c +++ b/test/parser_integration_tests.c @@ -4,6 +4,12 @@ #include #include +// switch this on to output all syntax errors +#define SHOW_ERRORS true + +// Mock a file with a `const char*` and return an error. +// NOTE: A valid argument must have a newline in the end otherwise it doesn't +// work. enum SYNTAX_ERROR setupError(const char *mockData) { FILE *mockFile = fmemopen((void *)mockData, strlen(mockData), "r"); @@ -23,8 +29,9 @@ enum SYNTAX_ERROR setupError(const char *mockData) { .fd = mockFile, .lineCount = lineCount, .token = token}; enum SYNTAX_ERROR error = prog(&parser); - // example debugging: - // printSyntaxError(error); + if (SHOW_ERRORS) { + printSyntaxError(error, parser.lineCount); + } return error; } @@ -156,3 +163,217 @@ void declDefProcProtoTwoProts() { enum SYNTAX_ERROR error = setupError("prot j(int) prot k(2(\n"); assert(error == INVALID_PROTO_PARAM_TYPE); } + +void declDefProcDefDefWorksToo() { + enum SYNTAX_ERROR error = setupError("def init)\n"); + assert(error == INVALID_DEF_PAREN_OPEN); + + enum SYNTAX_ERROR error2 = setupError("def 8\n"); + assert(error2 == NO_DEF_ID); +} + +void declDefProcDefNoParenOpen() { + enum SYNTAX_ERROR error = setupError("def init[\n"); + assert(error == INVALID_DEF_PAREN_OPEN); +} + +void declDefProcDefBadParamType() { + enum SYNTAX_ERROR error = setupError("def indio(&string\n"); + assert(error == INVALID_DEF_PARAM_TYPE); +} + +void declDefProcDefNoParamId() { + enum SYNTAX_ERROR error = setupError("def radio(int 8)"); + assert(error == NO_DEF_PARAM_ID); +} + +void declDefProcDefNoValidTokenAfterId() { + enum SYNTAX_ERROR error = setupError("def cesio(int a("); + assert(error == NO_DEF_VALID_TOKEN_AFTER_ID); +} + +void declDefProcDefValidTokenAfterClosePar() { + enum SYNTAX_ERROR error = setupError("def carbono(char ch) 8"); + assert(error == NO_DEF_VALID_TOKEN_AFTER_PAREN); +} + +void declDefProcDefArrayBadSubscriptType() { + enum SYNTAX_ERROR error = setupError("def sodio(char ch['a'])"); + assert(error == INVALID_ARRAY_DEF_PARAM_SUBSCRIPT_TYPE); +} + +void declDefProcDefArrayUnclosedBracket() { + enum SYNTAX_ERROR error = setupError("def uranio(int z[8[)"); + assert(error == INVALID_ARRAY_DEF_PARAM_BRACKET_CLOSE); +} + +void declDefProcDefArrayMultidimension() { + enum SYNTAX_ERROR error = setupError("def galio(int j[8][8[)"); + assert(error == INVALID_ARRAY_DEF_PARAM_BRACKET_CLOSE); +} + +void declDefProcDefArrayMultiParamMultiDimension() { + enum SYNTAX_ERROR error = setupError("def galio(int j[8][8], char x[4][3[)"); + assert(error == INVALID_ARRAY_DEF_PARAM_BRACKET_CLOSE); +} + +void declDefProcDefFollowedByDeclListVarError() { + enum SYNTAX_ERROR error = setupError("def litio(int i) const string"); + assert(error == INVALID_TYPE); +} + +void declDefProcDefFollowedByCmdError() { + enum SYNTAX_ERROR error = setupError("def plutonio(int i) getint 1"); + assert(error == NO_GETINT_ID); +} + +// test for cmd error after valid def and decl_list_var +void declDefProcDefFollowedByDeclListVarFollowedByCmdError() { + enum SYNTAX_ERROR error = + setupError("def plutonio(int i) const int n getint 1"); + assert(error == NO_GETINT_ID); +} + +// test for cmd error after valid def and multiple decl_list_var +void declDefProcDefFollowedByMultipleDeclListVarFollowedByCmdError() { + enum SYNTAX_ERROR error = + setupError("def plutonio(int i) const int n const int g getint 1"); + assert(error == NO_GETINT_ID); +} + +// multiple cmds +void declDefProcDefFollowedByMultipleCmdError() { + enum SYNTAX_ERROR error = + setupError("def plutonio(int i, int j) getint i getint 44"); + assert(error == NO_GETINT_ID); +} +// more exhaustive tests could be made, but I have work to do + +// test for no endp error +void declDefProcDefFollowedByABunchOfStuffButNotFinishingWithEndp() { + enum SYNTAX_ERROR error = + setupError("def galibdenio(int i) const int n getint n prot"); + assert(error == NO_DEF_END_KEYWORD); +} + +// a perfectly valid variable declaration-only program +void perfectlyValidVariableDeclarationOnlyProgram() { + enum SYNTAX_ERROR error = + setupError("const int a const int b char ch, chz\n"); + assert(error == NO_ERROR); +} + +// a perfectly valid function prototype declaration-only program +void perfectlyValidPrototypeOnlyProgram() { + enum SYNTAX_ERROR error = + setupError("prot soma(int, int) prot reduce(int[])\n"); + assert(error == NO_ERROR); +} + +// a perfectly valid function definition-only program +void perfectlyValidFunctionDefinitionOnlyProgram() { + enum SYNTAX_ERROR error = + setupError("def init (int self) endp def main (int arg) endp\n"); + assert(error == NO_ERROR); +} + +// a perfectly valid program with variable list declaration, then prototype, +// then definition then variable list declaration then cmd then endp +void perfectlyValidProgramWithDeclListVarThenProtThenDefThenDeclListVarThenCmdThenEndp() { + enum SYNTAX_ERROR error = + setupError("int num prot soma(int, int) def soma(int a, int b) int teste " + "= 5 getint teste endp\n"); + assert(error == NO_ERROR); +} + +void butEndpWasNotThere() { + enum SYNTAX_ERROR error = + setupError("int num prot soma(int, int) def soma(int a, int b) int teste " + "= 5 getint teste\n"); + assert(error == NO_DEF_END_KEYWORD); +} + +// from here onwards, integration tests will be a challenge. +// many routines depend on each other. + +void getoutWorks() { + enum SYNTAX_ERROR error = setupError("def calcio(char c) getout\n"); + assert(error == NO_DEF_END_KEYWORD); +} + +void getrealError() { + enum SYNTAX_ERROR error = setupError("def magnesio(char c) getreal 5\n"); + assert(error == NO_GETREAL_ID); +} + +void getcharError() { + enum SYNTAX_ERROR error = setupError("def manganes(char c) getchar 5\n"); + assert(error == NO_GETCHAR_ID); +} + +void getstrError() { + enum SYNTAX_ERROR error = setupError("def titanio(char c) getstr 5\n"); + assert(error == NO_GETSTR_ID); +} + +void putintError() { + enum SYNTAX_ERROR error = setupError("def titanio(char c) putint 2.2\n"); + assert(error == INVALID_PUTINT_ELEMENT); +} + +void putrealError() { + enum SYNTAX_ERROR error = setupError("def titanio(char c) putreal 'a'\n"); + assert(error == INVALID_PUTREAL_ELEMENT); +} + +void putcharError() { + enum SYNTAX_ERROR error = setupError("def titanio(char c) putchar 8\n"); + assert(error == INVALID_PUTCHAR_ELEMENT); +} + +void putstrError() { + enum SYNTAX_ERROR error = setupError("def titanio(char c) putstr 8\n"); + assert(error == INVALID_PUTSTR_ELEMENT); +} + +// do no idproc error +void doButNotIdproc() { + enum SYNTAX_ERROR error = setupError("def adamantio(int i) do 8\n"); + assert(error == INVALID_FUNCTION_CALL_ID); +} + +// do idproc paren error +void doButNoParenOpen() { + enum SYNTAX_ERROR error = setupError("def tritio(int i) do tritio)\n"); + assert(error == INVALID_FUNCTION_CALL_PAREN_OPEN); +} + +// tests with atrib might help developing expr... i hope ;-; + +// atrib no valid after id + +void atribNoValidAfterId() { + enum SYNTAX_ERROR error = setupError("def potassio(int i) i 8"); + assert(error == NO_ATRIB_VALID_TOKEN_AFTER_ID); +} + +// atrib with assignment to a bad expr: a stringcon +void atribAssignedToABadExprAStringcon() { + enum SYNTAX_ERROR error = setupError("def potassio(int i) i = $"); + assert(error == NO_FACTOR_VALID_START_SYMBOL); +} + +void doButNoClosingParen() { + enum SYNTAX_ERROR error = setupError("def nitrogenio(int i) do nitrogenio(8("); + assert(error == INVALID_FUNCTION_CALL_PAREN_CLOSE); +} + + +// TODO: +// +// atrib with bad unclosed paren +/*void atribBadClosedParen() {*/ +/* enum SYNTAX_ERROR error = setupError("def oxigenio(int i) id[8[");*/ +/* assert(error == NO_ATRIB_BRACKET_CLOSE);*/ +/*}*/ + diff --git a/test/parser_integration_tests.h b/test/parser_integration_tests.h index 15b908b..1b65a06 100644 --- a/test/parser_integration_tests.h +++ b/test/parser_integration_tests.h @@ -37,4 +37,49 @@ void declDefProcProtoMultiParams(); void declDefProcProtoNoParenClose(); void declDefProcProtoTwoProts(); +void declDefProcDefDefWorksToo(); +void declDefProcDefNoParenOpen(); +void declDefProcDefBadParamType(); +void declDefProcDefNoParamId(); +void declDefProcDefNoValidTokenAfterId(); +void declDefProcDefValidTokenAfterClosePar(); + +void declDefProcDefArrayBadSubscriptType(); +void declDefProcDefArrayUnclosedBracket(); +void declDefProcDefArrayMultidimension(); +void declDefProcDefArrayMultiParamMultiDimension(); + +void declDefProcDefFollowedByDeclListVarError(); +void declDefProcDefFollowedByCmdError(); +void declDefProcDefFollowedByDeclListVarFollowedByCmdError(); +void declDefProcDefFollowedByMultipleDeclListVarFollowedByCmdError(); +void declDefProcDefFollowedByMultipleCmdError(); +void declDefProcDefFollowedByABunchOfStuffButNotFinishingWithEndp(); + +void perfectlyValidVariableDeclarationOnlyProgram(); +void perfectlyValidPrototypeOnlyProgram(); +void perfectlyValidFunctionDefinitionOnlyProgram(); +void perfectlyValidProgramWithDeclListVarThenProtThenDefThenDeclListVarThenCmdThenEndp(); +void butEndpWasNotThere(); + +void getoutWorks(); +void getrealError(); +void getcharError(); +void getstrError(); +void putintError(); +void putrealError(); +void putcharError(); +void putstrError(); + +void doButNotIdproc(); +void doButNoParenOpen(); +void doButNoClosingParen(); +// test expression list too + +void atribNoValidAfterId(); +void atribAssignedToABadExprAStringcon(); +void atribBadClosedParen(); + +// void doIdprocExprExprSimpTermoFatorNoValidTokenAfterId(); + #endif // !PARSER_INTEGRATION_TESTS_H diff --git a/test/test.c b/test/test.c index 03165d9..186bbef 100644 --- a/test/test.c +++ b/test/test.c @@ -14,7 +14,7 @@ int main(void) { lexerCharconTest(); lexerCharconTest2(); - printf(GREEN "--- Lexer tests passed\n" RESET); + printf("--- Lexer tests passed\n"); opRelTest(); opRelTest2(); @@ -27,7 +27,7 @@ int main(void) { declVarArrayBadInitCurly(); // fatorArrayMultTest(); - printf(GREEN "--- Parser unit tests passed\n" RESET); + printf("--- Parser unit tests passed\n"); progStartKeyword(); @@ -57,7 +57,47 @@ int main(void) { declDefProcProtoNoParenClose(); declDefProcProtoTwoProts(); - printf(GREEN "--- Parser integration tests passed\n" RESET); + declDefProcDefDefWorksToo(); + declDefProcDefNoParenOpen(); + declDefProcDefBadParamType(); + declDefProcDefNoParamId(); + declDefProcDefNoValidTokenAfterId(); + declDefProcDefValidTokenAfterClosePar(); + declDefProcDefArrayBadSubscriptType(); + declDefProcDefArrayUnclosedBracket(); + declDefProcDefArrayMultidimension(); + declDefProcDefArrayMultiParamMultiDimension(); + + declDefProcDefFollowedByDeclListVarError(); + declDefProcDefFollowedByCmdError(); + declDefProcDefFollowedByDeclListVarFollowedByCmdError(); + + perfectlyValidVariableDeclarationOnlyProgram(); + perfectlyValidPrototypeOnlyProgram(); + perfectlyValidFunctionDefinitionOnlyProgram(); + perfectlyValidProgramWithDeclListVarThenProtThenDefThenDeclListVarThenCmdThenEndp(); + butEndpWasNotThere(); + + getoutWorks(); + getrealError(); + getcharError(); + getstrError(); + putintError(); + putrealError(); + putcharError(); + putstrError(); + + doButNotIdproc(); + doButNoParenOpen(); + doButNoClosingParen(); + + atribNoValidAfterId(); + atribAssignedToABadExprAStringcon(); + // atribBadClosedParen(); + + printf("--- Parser integration tests passed\n"); + + printf(GREEN "All tests OK\n" RESET); return EXIT_SUCCESS; }