diff --git a/backend/irgen.c b/backend/irgen.c index 8f644b1..65dd43d 100644 --- a/backend/irgen.c +++ b/backend/irgen.c @@ -21,6 +21,7 @@ static unsigned l; /* Returns a corresponding C type for a given MP_ or TT_ */ static const char *getCType (unsigned tt) { switch (tt) { + case UNDEFINED: return "void"; case TT_INTEGER: return "int"; case MP_INTEGER: return "int"; case TT_REAL: return "double"; @@ -67,6 +68,26 @@ static const char *invOp (unsigned operator) { exit(EXIT_FAILURE); } +/* Writes a comma delimited list of C-type datatypes to given FILE */ +static void writeDataList (FILE *fp, dataListType dataList, unsigned onlyId) { + for (int i = 0; i < dataList.length; i++) { + dataType *dt = dataList.list[i]; + const char *p = (dt->tc == TC_VECTOR) ? "[]" : ""; + if (onlyId) { + if (dt->id == NIL) { + fprintf(fp, "t%u", dt->tn); + } else { + fprintf(fp, "%s", identifierAtIndex(dt->id)); + } + } else { + fprintf(fp, "%s %s%s", getCType(dt->tt), identifierAtIndex(dt->id), p); + } + if (i < dataList.length - 1) { + fprintf(fp, ", "); + } + } +} + /* *************************************************************************** * Expression Generation Routines @@ -84,8 +105,12 @@ unsigned genConst (unsigned tt, double n) { } /* Generates a T-Label for given identifier. Returns T-Label num */ -unsigned genId (unsigned tt, const char *identifier) { - fprintf(irfp, "%s t%u = %s;\n", getCType(tt), t, identifier); +unsigned genId (unsigned tc, unsigned tt, const char *identifier) { + if (tc == TC_SCALAR) { + fprintf(irfp, "%s t%u = %s;\n", getCType(tt), t, identifier); + } else { + fprintf(irfp, "%s *t%u = %s;\n", getCType(tt), t, identifier); + } return t++; } @@ -115,6 +140,39 @@ unsigned genBoolOp (unsigned tx, unsigned ty) { return t++; } +/* Generates a T-Label for a function invocation. Returns T-Label num. */ +unsigned genFuncCall (unsigned tt, const char *name, dataListType args) { + + // Generate call head. + fprintf(irfp, "%s t%u = %s", getCType(tt), t, name); + + // Generate args. + putc('(', irfp); + writeDataList(irfp, args, 1); + putc(')', irfp); + + // Generate call end. + fprintf(irfp, ";\n"); + + return t++; +} + +/* Generates a T-Label for a procedure invocation. No label returned. */ +void genProcCall (const char *name, dataListType args) { + + // Generate call head. + fprintf(irfp, "%s", name); + + // Generate args. + putc('(', irfp); + writeDataList(irfp, args, 1); + putc(')', irfp); + + // Generate call end. + fprintf(irfp, ";\n"); +} + + /* *************************************************************************** * Assignment Generation Routines @@ -187,6 +245,33 @@ void genVectorDec (unsigned tt, unsigned n, const char *identifier) { fprintf(irfp, "%s %s[%d];\n", getCType(tt), identifier, n); } +/* +*************************************************************************** +* Routine Generation Routines +*************************************************************************** +*/ + +/* Generates a routine declaration */ +void genRoutineDec (unsigned tt, const char *name, dataListType args) { + + // Install return type and name. + fprintf(irfp, "%s %s", getCType(tt), name); + + // Install arguments */ + putc('(', irfp); + writeDataList(irfp, args, 0); + putc(')', irfp); +} + +/* Generates a routine return statement */ +void genReturn (unsigned tt, unsigned id) { + if (tt == UNDEFINED) { + fprintf(irfp, "return;\n"); + } else { + fprintf(irfp, "return %s;\n", identifierAtIndex(id)); + } +} + /* *************************************************************************** * Structural Generation Routines @@ -203,6 +288,16 @@ void genMainEnd () { fprintf(irfp, "return 0;\n}\n"); } +/* Generates the opening of a block (newline + Opening brace + newline) */ +void genBlockStart() { + fprintf(irfp, "\n{\n"); +} + +/* Generates the end of a block (newline + Closing brace + newline) */ +void genBlockEnd() { + fprintf(irfp, "}\n"); +} + /* *************************************************************************** * Library Procedure Generation Routines diff --git a/backend/irgen.h b/backend/irgen.h index 4be1cdb..bbc8999 100644 --- a/backend/irgen.h +++ b/backend/irgen.h @@ -33,7 +33,7 @@ extern FILE *irfp; unsigned genConst (unsigned tt, double n); /* Generates a T-Label for given identifier. Returns T-Label num */ -unsigned genId (unsigned tt, const char *identifier); +unsigned genId (unsigned tc, unsigned tt, const char *identifier); /* Generates a T-Label for an T-indexed vector. Returns T-Label num. */ unsigned genVecIdx (unsigned tt, const char *identifier, unsigned ti, unsigned vb); @@ -47,6 +47,12 @@ unsigned genArithOp (unsigned tt, unsigned operator, unsigned tx, unsigned ty); /* Generates a T-Label for a boolean operation (tx - ty). Returns T-Label num. */ unsigned genBoolOp (unsigned tx, unsigned ty); +/* Generates a T-Label for a function invocation. Returns T-Label num. */ +unsigned genFuncCall (unsigned tt, const char *name, dataListType args); + +/* Generates a T-Label for a procedure invocation. No label returned. */ +void genProcCall (const char *name, dataListType args); + /* *************************************************************************** * Assignment Generation Prototypes @@ -95,6 +101,18 @@ void genScalarDec (unsigned tt, const char *identifier); /* Generates a vector decalaration. */ void genVectorDec (unsigned tt, unsigned n, const char *identifier); +/* +*************************************************************************** +* Routine Generation Prototypes +*************************************************************************** +*/ + +/* Generates a routine declaration */ +void genRoutineDec (unsigned tt, const char *name, dataListType args); + +/* Generates a routine return statement */ +void genReturn (unsigned tt, unsigned id); + /* *************************************************************************** * Structural Generation Prototypes @@ -107,6 +125,12 @@ void genMainHeader (); /* Generates the return statement and closing brace for main */ void genMainEnd (); +/* Generates the opening of a block (Opening brace + newline) */ +void genBlockStart(); + +/* Generates the end of a block (Closing brace + newline) */ +void genBlockEnd(); + /* *************************************************************************** * Library Procedure Generation Prototypes diff --git a/backend/mpascal.y b/backend/mpascal.y index eb6dd5f..587f7bb 100644 --- a/backend/mpascal.y +++ b/backend/mpascal.y @@ -127,10 +127,10 @@ int yyerror(char *s) { } // Nonterminal return type rules. -%type standardType sign identifier -%type type +%type standardType sign identifier +%type type subprogramHead %type variable expression factor term simpleExpression -%type declarations identifierList expressionList +%type declarations identifierList expressionList parameterList arguments // Starting Grammar Rule. %start program @@ -205,20 +205,93 @@ subprogramDeclarations : subprogramDeclarations subprogramDeclaration MP_SCOLON | ; -subprogramDeclaration : subprogramHead declarations - compoundStatement +subprogramDeclaration : subprogramHead { /* Generate the opening brace after the header */ + genBlockStart(); + } + declarations { + /* If the routine is a function, install a local scalar declaration to return */ + if ($1.tc != UNDEFINED) { + installIdEntry($1.tt, TC_SCALAR, $1.tc, 0, 0); + genScalarDec($1.tc, identifierAtIndex($1.tt)); + } + + /* Install all remaining local variable declarations. */ + for (int i = 0; i < $3.length; i++) { + dataType *d = $3.list[i]; + + /* Install each entry into the symbol table */ + installIdEntry(d->id, d->tc, d->tt, d->vb, d->vl); + + /* Generate an appropriate declaration (Vector | Scalar) */ + if (d->tc == TC_VECTOR) { + genVectorDec(d->tt, d->vl, identifierAtIndex(d->id)); + } else { + genScalarDec(d->tt, identifierAtIndex(d->id)); + } + } + + /* Clean up allocated memory */ + freeDataList($3); + } + compoundStatement { /* Generate the return statement, close the block, and decrement table scope */ + genReturn($1.tc, $1.tt); genBlockEnd(); decrementTableScope(); + } ; -subprogramHead : MP_FUNCTION identifier arguments MP_COLON standardType MP_SCOLON - | MP_PROCEDURE identifier arguments MP_SCOLON +subprogramHead : MP_FUNCTION identifier arguments MP_COLON standardType MP_SCOLON { /* Install function header */ + genRoutineDec($5, identifierAtIndex($2), $3); + + /* Install entry: Vector-Count (vc) stores arg count */ + installIdEntry($2, TC_ROUTINE, $5, 0, $3.length); + + /* Increment table scope before installing arguments */ + incrementTableScope(); + + /* Install arguments */ + for (int i = 0; i < $3.length; i++) { + dataType *d = $3.list[i]; + + /* Install each entry into the symbol table */ + installIdEntry(d->id, d->tc, d->tt, d->vb, d->vl); + } + + /* Free allocated memory */ + freeDataList($3); + + /* Custom DescType (.tc = Return Token-Type, .tt = Routine Name) */ + $$ = (descType){.tc = $5, .tt = $2, .vb = 0, .vl = 0}; + } + | MP_PROCEDURE identifier arguments MP_SCOLON { /* Install void function header */ + genRoutineDec(UNDEFINED, identifierAtIndex($2), $3); + + /* Install entry: Vector-Count (vc) stores arg count */ + installIdEntry($2, TC_ROUTINE, UNDEFINED, 0, $3.length); + + /* Increment table scope before installing arguments */ + incrementTableScope(); + + /* Install arguments */ + for (int i = 0; i < $3.length; i++) { + dataType *d = $3.list[i]; + + /* Install each entry into the symbol table */ + installIdEntry(d->id, d->tc, d->tt, d->vb, d->vl); + } + + /* Free allocated memory */ + freeDataList($3); + + /* Custom DescType (.tc = Return Token-Type, .tt = Routine Name) */ + $$ = (descType){.tc = UNDEFINED, .tt = $2, .vb = 0, .vl = 0}; + } ; -arguments : MP_POPEN parameterList MP_PCLOSE - | +arguments : MP_POPEN parameterList MP_PCLOSE { $$ = $2; } + | { $$ = initDataListType(); } ; -parameterList : identifierList MP_COLON type - | parameterList MP_SCOLON identifierList MP_COLON type +parameterList : identifierList MP_COLON type { $$ = mapDescToDataList($3, $1); } + | parameterList MP_SCOLON identifierList MP_COLON type { $$ = appendDataList(mapDescToDataList($5, $3), $1); } ; compoundStatement : MP_BEGIN optionalStatements MP_END @@ -261,10 +334,15 @@ variable : identifier { /* Initializ } procedureStatement : identifier - | identifier MP_POPEN expressionList MP_PCLOSE { /* Procedure calls are disabled */ + | identifier MP_POPEN expressionList MP_PCLOSE { /* Procedure call */ + + /* Extract routine IdEntry */ + + /* Generate routine call */ + genProcCall(identifierAtIndex($1), $3); + + /* Free allocated memory */ freeDataList($3); - fprintf(stderr, "Error: Procedure calls are not available!\n"); - exit(EXIT_FAILURE); } | MP_READLN MP_POPEN expressionList MP_PCLOSE { /* Generate corresponding readln function in C. */ genReadLn($3); @@ -310,12 +388,18 @@ term : factor { $$ = $1; } factor : identifier { /* Extracting Entry and populating dataType fields. */ IdEntry *entry = containsIdEntry($1, TC_ANY, SYMTAB_SCOPE_ALL); - $$ = initExprVarDataType(genId(entry->tt, identifierAtIndex($1)), entry->tc, entry->tt, $1); + $$ = initExprVarDataType(genId(entry->tc, entry->tt, identifierAtIndex($1)), entry->tc, entry->tt, $1); } - | identifier MP_POPEN expressionList MP_PCLOSE { /* This is currently disabled */ + | identifier MP_POPEN expressionList MP_PCLOSE { /* Function call */ + + /* Extract routine IdEntry */ + IdEntry *entry = containsIdEntry($1, TC_ROUTINE, SYMTAB_SCOPE_ALL); + + /* Generate routine call */ + $$ = initExprConstDataType(genFuncCall(entry->tt, identifierAtIndex($1), $3), entry->tt); + + /* Free allocated memory */ freeDataList($3); - fprintf(stderr, "Error: Function calls are not available!\n"); - exit(EXIT_FAILURE); } | identifier MP_BOPEN expression MP_BCLOSE { /* Extracting Entry. Generating indexed variable code */ diff --git a/backend/mptypes.c b/backend/mptypes.c index abd2e96..23ec87d 100644 --- a/backend/mptypes.c +++ b/backend/mptypes.c @@ -13,7 +13,8 @@ dataType *allocDataType (void) { fprintf(stderr, "Error: allocDataType: Couldn't allocate memory!\n"); exit(EXIT_FAILURE); } - dt->id = dt->tc = dt->tt = dt->ti = dt->tn = dt->vb = dt->vl = dt->op = UNDEFINED; + dt->tc = dt->tt = dt->ti = dt->tn = dt->vb = dt->vl = dt->op = UNDEFINED; + dt->id = NIL; return dt; } diff --git a/backend/symtab.c b/backend/symtab.c index 24ca7d9..922f7f4 100644 --- a/backend/symtab.c +++ b/backend/symtab.c @@ -230,7 +230,7 @@ IdEntry *installIdEntry (unsigned id, unsigned tc, unsigned tt, unsigned vb, uns // Verify entry does not exist yet. if ((lp = listContains(id, tc, symTable[h][lvl])) != NULL) { - fprintf(stderr, "Error: installIdEntry: Entry already exists in table!\n"); + fprintf(stderr, "Error: installIdEntry: Entry %s already exists in table!\n", identifierAtIndex(id)); exit(EXIT_FAILURE); }