/* Università di Bologna Corso di laurea in Informatica 11925 - Architettura degli elaboratori Stefano Volpe #969766 04/12/2020 parser.c Implementation of the module which handles the parsing of a single .vm file, and encapsulates access to the input code. */ #include <ctype.h> #include <stdlib.h> #include <string.h> #include "parser.h" #define N_KEYWORDS 17 #define STR(x) #x #define EXPAND(x) STR(x) const struct { char keyword[SYMBOL_DIM + 1]; enum instructiontype commandtype; } keywordsemantics[N_KEYWORDS] = { "add", C_ARITHMETIC, "sub", C_ARITHMETIC, "neg", C_ARITHMETIC, "eq", C_ARITHMETIC, "gt", C_ARITHMETIC, "lt", C_ARITHMETIC, "and", C_ARITHMETIC, "or", C_ARITHMETIC, "not", C_ARITHMETIC, "push", C_PUSH, "pop", C_POP, "label", C_LABEL, "goto", C_GOTO, "if-goto", C_IF, "function", C_FUNCTION, "return", C_RETURN, "call", C_CALL }; // converts a keyword to the corresponding instruction type enum instructiontype toinstructiontype(const char *); // empties all argN fields of the instruction, but not its type void cleancommand(struct input *); // ignores whitespaces until the next relevant character void parserignore(FILE *); // exits the program warning the user about the error encountered void parseerror(FILE *, const int code, const char *desc); struct input inputconstruct(const char *filename) { struct input i; if (!(i.stream = fopen(filename, "r"))) { fprintf(stderr, "Accesso al file '%s' fallito.\n", filename); exit(-1); } i.commandtype = NO_COMMAND; cleancommand(&i); return i; } bool hasmorecommands(const struct input i) { parserignore(i.stream); return !feof(i.stream); } void advance(struct input *i) { if (!hasmorecommands(*i)) return; cleancommand(i); char s[SYMBOL_DIM]; fscanf(i->stream, "%" EXPAND(SYMBOL_DIM) "s", s); switch(i->commandtype = toinstructiontype(s)) { case C_ARITHMETIC: strcpy(i->arg1, s); break; case C_PUSH: case C_POP: case C_FUNCTION: case C_CALL: fscanf(i->stream, "%" EXPAND(SYMBOL_DIM) "s%d", i->arg1, &i->arg2); break; case C_LABEL: case C_GOTO: case C_IF: fscanf(i->stream, "%" EXPAND(SYMBOL_DIM) "s", i->arg1); break; case NO_COMMAND: parseerror(i->stream, 1, "nome istruzione ignoto"); } } void inputdestroy(struct input *i) { fclose(i->stream); i->commandtype = NO_COMMAND; } enum instructiontype toinstructiontype(const char *s) { for (size_t i = 0; i < N_KEYWORDS; ++i) if (!strcmp(keywordsemantics[i].keyword, s)) return keywordsemantics[i].commandtype; return NO_COMMAND; } void cleancommand(struct input *i) { strcpy(i->arg1, "\0"); i->arg2 = 0; } void parserignore(FILE *f) { char c = ' '; while (!feof(f) && isspace(c)) { c = fgetc(f); if (c == '/') // line comments while (!feof(f) && c != '\n') c = fgetc(f); } if (!feof(f)) ungetc(c, f); } void parseerror(FILE *f, const int code, const char *desc) { fprintf(stderr, "Errore %d in %d: %s\n", code, ftell(f), desc); exit(code); }