/* This file defines the grammar for a Jay language program. * If provided as input to the standard UNIX tool yacc, it * generates a program that parses a Jay language program and * produces an intermediate representation of the program analogous * to a parse tree. The main function for this program can be found * at the bottom of this file, in the CODE SECTION. The parsing * program expects an input file containing a Jay program to be * provided using standard input, and write the parse tree * representation to standard output. * * Alyce Brady * 14 October, 2006 */ /* DEFINITIONS SECTION */ /* First, provide any C code that should appear at the beginning of * the parser code. In this case, read in the header file * that defines the codes that represent various language * constructs, declares global variables shared by lex and yacc, etc. */ %{ #include #include #include "jayParser.h" %} /* Identify the categories of tokens to be recognized by lex. */ /* Types */ %token JAYTYPE /* Statement keywords */ %token ASSIGN %token IF %token ELSE %token WHILE /* Binary Operations (in reverse precedence) */ %left EQUIV %left RELOP %left ADDSUB %left MULTDIV /* Punctuation */ %token SEMI %token LBRACE %token RBRACE %token LPAREN %token RPAREN %token COMMA /* Constants and Identifiers */ %token INT_CONSTANT %token IDENTIFIER %token MAIN /* Non-terminals that have typed values (usually strings) */ %type identList %type expression %type condition %type bool_expr %type primary /* %type exprList */ /* Start symbol: */ %start jayProgram %% /* RULES SECTION */ /* Overall program */ jayProgram : /* empty */ { } | error { /* Clear state. */ yyerrok; } | jayProgram procedure_def { } ; procedure_def : main { } ; /* Main: a very specific type of procedure/function definition */ main : JAYTYPE MAIN LPAREN RPAREN { if ( $1 != Void ) yyerror("main must be a void procedure"); else { printIndentation(indent_amt); printf("%s main()\n", keywords[$1]); } } procedureBody ; procedureBody : LBRACE { printIndentation(indent_amt); printf("{\n"); indent_amt += INDENT_OFFSET; } optlocaldefs statements RBRACE { indent_amt -= INDENT_OFFSET; printIndentation(indent_amt); printf("}\n"); } ; optlocaldefs : /* empty */ { } | optlocaldefs localdef ; localdef : error SEMI { /* Clear state. */ yyerrok; } | JAYTYPE identList SEMI { printIndentation(indent_amt); printf("%s %s;\n", keywords[$1], $2); } ; identList : IDENTIFIER { } | identList COMMA IDENTIFIER { $$ = buildListString($1, $3); } ; statements : /* empty */ { } | statements statement { } ; statement : error SEMI { /* Clear state. */ yyerrok; } | SEMI { printIndentation(indent_amt); printf(";\n"); } | IDENTIFIER ASSIGN expression SEMI { printIndentation(indent_amt); printf("%s = %s;\n", $1, $3); } | WHILE condition { printIndentation(indent_amt); printf("while ( %s )\n", $2); indent_amt += INDENT_OFFSET; } statementOrBlock { indent_amt -= INDENT_OFFSET; } ; condition : LPAREN bool_expr RPAREN { $$ = $2; } | LPAREN error RPAREN { /* Clear state. */ yyerrok; } ; statementOrBlock : statement { } | LBRACE { printIndentation(indent_amt - INDENT_OFFSET); printf("{\n"); } statements RBRACE { printIndentation(indent_amt - INDENT_OFFSET); printf("}\n"); } | error RBRACE { /* Clear state. */ yyerrok; } ; expression : INT_CONSTANT { } | primary { } | expression ADDSUB expression { $$ = buildBinOpString($1, keywords[$2], $3); } /* | bool_expr { } */ ; primary : IDENTIFIER { } /* | LPAREN expression RPAREN { } */ /* | primary LPAREN exprList RPAREN */ /* | primary LPAREN RPAREN */ ; /* This assumes that we don't have boolean constants or variables, which * is a poor assumption since Jay has a boolean type. */ bool_expr : expression RELOP expression { $$ = buildBinOpString($1, keywords[$2], $3); } | expression EQUIV expression { $$ = buildBinOpString($1, keywords[$2], $3); } ; /* Following is not necessary unless we support function calls. exprList : expression { } | exprList COMMA expression { $$ = buildListString($1, $3); } ; */ %% /* CODE SECTION */ /* Define global variable(s). */ const int SAME = 0; /* useful for writing readable strcmp calls */ const int INDENT_OFFSET = 4; /* how much to change indentation by */ unsigned int line_count; /* line count (for error messages) */ int indent_amt = 0; /* indentation amount (for pretty-printing) */ int buffer_cap; /* capacity of buffer for storing long strings */ string_type buffer; /* buffer for storing long strings */ string_type keywords[] = {"main", "boolean", "int", "void", "=", "if", "else", "while", ";", "+", "-", "*", "/", "==", "!=", "<", ">", "<=", ">=", "{", "}", "(", ")", "," }; /* Provide function declarations for local functions. */ void printIndentation(int n); string_type buildListString(string_type o1, string_type o2); string_type buildBinOpString(string_type o1, string_type op, string_type o2); void yyerror(string_type s); /* Main function for the Jay Parser program. */ int main() { int return_code; line_count = 1; buffer_cap = 80; // initialize capacity of buffer for long strings buffer = malloc(buffer_cap); return_code = yyparse(); return (return_code); } /* Function to indent lines of code appropriately. */ void printIndentation(int n) { int i; for ( i = 0; i < n; i++ ) putchar(' '); } /* Function to build a string containing a list. */ string_type buildListString(string_type o1, string_type o2) { string_type string = malloc(strlen(o1) + strlen(o2) + 3); (void)sprintf(string, "%s, %s", o1, o2); free(o1); free(o2); return string; } /* Function to build a string containing a binary operation. */ string_type buildBinOpString(string_type o1, string_type op, string_type o2) { string_type string = malloc(strlen(o1) + strlen(op) + strlen(o2) + 3); (void)sprintf(string, "%s %s %s", o1, op, o2); free(o1); free(o2); return string; } /* Function to print error messages to stderr. */ void yyerror(string_type s) { if ( strcmp(s, "syntax error") == SAME ) { (void) fprintf(stderr, "%s at or near ", s); if ( yychar <= 0 ) (void) fprintf(stderr, "EOF"); else if ( yychar <= RPAREN ) (void) fprintf(stderr, keywords[(int)yylval.keyword]); else (void) fprintf(stderr, yylval.stringrep); (void) fprintf(stderr, " on line %u\n", line_count); } else (void) fprintf(stderr, "%s on or about line %u\n", s, line_count); return; }