/* * Copyrigth (C) 2002 Marcello Barnaba * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Christopher G. Demetriou. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Simple pascal rules. * Developed on NetBSD/macppc and linux/i386. */ %expect 14 %{ #include "vp.h" #define YYERROR_VERBOSE #define error yyerror #ifndef __cplusplus #define bool char #define true 1 #define false 0 #endif typedef struct loc { struct { int line; int pos; } location; struct loc *next; } loc; typedef struct tnode { unsigned char *name; int type; int count; loc *locations; struct tnode *left, *right; } tnode; char *yylbuf; extern int line_num; extern int pos_num; extern char *yytext; extern int yylex(); void yyerror(char *); void warning(char *); void tree_add(tnode **, char *); tnode *symtable; %} /* grammar decls. */ /* identifiers. */ %token ID /* constants. */ %token INT_CONST %token REAL_CONST %token BOOL_CONST %token STRING /* reserved words. */ %token IF THEN ELSE BEGIN_ END WHILE DO REPEAT UNTIL VAR CASE %token OF DOTDOT FOR TO DOWNTO WITH %token PROCEDURE FUNCTION PROGRAM /* specifies no associativity, which means that `X OP Y OP Z' is considered a syntax error. */ %nonassoc IF %nonassoc ELSE /* predef types */ %token INTEGER REAL BOOLEAN CHAR %token ASSIGN NE GE LE OR DIV MOD AND NOT /* operators. */ %right ASSIGN %binary '<' '=' '>' NE GE LE %left '-' '+' OR %left '/' '*' DIV MOD AND %left NOT /* NT types. */ /* %type ASSIGN %type ID %type rest_of_statement %type expression %type identifier %type id_list %type variable %type variable_type %type predef_type */ %start program %% /* start symbol */ program: program_declarations dot ; dot: '.' | error { error("missing '.' at EOF"); return 1; } ; program_declarations: optional_head /* optional PROGRAM line */ declarations /* global declarations */ statement_part /* main */ ; optional_head: /* lambda */ { warning("missing program heading"); } | head ';' ; head: PROGRAM identifier optional_param_list | PROGRAM error { error("missing program name"); } optional_param_list ; optional_param_list: /* lambda */ | '(' id_list ')' ; id_list: identifier { tree_add(&symtable, yytext); } | id_list ',' identifier | id_list error identifier { error("missing comma after identifier"); } | id_list ',' error { error("extra comma in identifier list"); } | id_list error { error("improper termination of identifier list"); } ; declarations: /* lambda */ | declaration_list ; declaration_list: any_declaration | declaration_list any_declaration ; any_declaration: variable_declaration | function_declaration ; variable_declaration: VAR variable_list ';' ; variable_list: variable | variable_list ';' variable | variable_list error variable { error("missing semicolon in variable list"); } | variable_list ';' error { error("extra semicolon in variable list"); } ; variable: id_list ':' variable_type ; predef_type: INTEGER | REAL | BOOLEAN | CHAR ; variable_type: ID | predef_type ; function_declaration: function_head ';' declarations compound_statement ';' ; function_head: PROCEDURE identifier optional_parameter_list | FUNCTION identifier optional_parameter_list ':' variable_type ; optional_parameter_list: /* lambda */ | '(' parameter_list ')' ; parameter_list: parameter | parameter_list ';' parameter | error { error("expected parameter"); } | parameter_list error parameter { error("missing semicolon in parameter list"); } | parameter_list ';' error { error("extra semicolon in parameter list"); } ; parameter: id_list ':' variable_type | VAR id_list ':' variable_type ; /* group of statements, NOT enclosed in BEGIN / END */ statement_list: /* lambda */ | statement | statement_list ';' statement | statement_list error statement { error("missing semi in statement list"); } | statement_list ';' error { error("extra semi in statement list"); } ; /* single statement */ statement: structured_statement /* sequence, choice and iteration */ | declaring_statement /* declarations */ | simple_statement /* assignment_or_call */ ; structured_statement: compound_statement /* BEGIN .. END block */ | conditional_statement /* IF and CASE blocks */ | iterative_statement /* WHILE and REPEAT blocks */ | with_statement /* WITH block */ ; /* code block in MAIN and FUNCTION/PROCEDURE */ statement_part: compound_statement ; /* BEGIN ..code.. [;] END */ compound_statement: BEGIN_ statement_list optional_semi END ; /* simple declaration */ declaring_statement: VAR id_list ':' variable_type ; /* conditionals */ conditional_statement: if_statement | case_statement ; /* IF */ simple_if: IF boolean_expression THEN_or_error statement ; THEN_or_error: THEN | error { error("missing 'then'"); } ; if_statement: simple_if ELSE statement | simple_if ; /* CASE */ case_statement: CASE expression OF_or_error case_element_list optional_semi END ; OF_or_error: OF | error { error("missing 'OF'"); } ; /* list of case elements */ case_element_list: case_element | case_element_list ';' case_element | error { error("case element expected"); } | case_element_list error case_element { error("missing semicolon in case elements list"); } | case_element_list ';' error { error("extra semicolon in case elements list"); } ; case_element: case_constant_list ':' statement ; /* list of case constants */ case_constant_list: case_constant | case_constant_list ',' case_constant | case_constant_list error case_constant { error("missing comma"); } | case_constant_list ',' error { error("extra comma"); } | case_constant_list error { error("improper termination of case constants list"); } ; case_constant: constant_expression | constant_expression DOTDOT constant_expression | constant_expression error constant_expression { error("missing '..'"); } | constant_expression DOTDOT error { error("extra '..'"); } ; /* iteration */ iterative_statement: repeat_statement | while_statement | for_statement ; /* REPEAT */ repeat_statement: REPEAT statement_list optional_semi UNTIL boolean_expression ; /* WHILE */ while_statement: WHILE boolean_expression DO statement_list optional_semi ; /* FOR */ for_statement: FOR assignment to_or_downto ID DO statement_list optional_semi ; to_or_downto: TO | DOWNTO ; /* assignment or call */ simple_statement: assignment_or_call_statement ; assignment: identifier ASSIGN expression ; assignment_or_call_statement: variable_or_function_access_no_id /* call with parameters */ | identifier /* call without parameters */ rest_of_statement /* possible assignment */ ; rest_of_statement: /* lambda */ | ASSIGN expression /* actual assignment */ ; with_statement: WITH identifier DO statement_list optional_semi ; /* expressions */ constant_expression: expression ; boolean_expression: expression ; actual_parameter: expression ; expression: simple_expression comparation_op simple_expression | simple_expression ; simple_expression: any_term | simple_expression plus_minus any_term | simple_expression OR any_term ; any_term: plus_minus term | term ; term: factor | term mul_div factor | term AND factor ; factor: variable_or_function_access | unsigned_number | BOOL_CONST | NOT factor ; variable_or_function_access: identifier | variable_or_function_access_no_id ; variable_or_function_access_no_id: '(' expression closepar_or_error | variable_or_function_access '(' actual_parameter_list closepar_or_error | '(' variable_or_function_access closepar_or_error ; actual_parameter_list: actual_parameter | actual_parameter_list ',' actual_parameter | actual_parameter_list error actual_parameter { error("missing comma"); } | actual_parameter_list ',' error { error("extra comma"); } ; /* main terminal-generators */ identifier: ID | STRING ; comparation_op: '=' | NE | '<' | '>' | LE | GE ; mul_div: '*' | '/' | DIV | MOD ; plus_minus: '+' | '-' ; closepar_or_error: ')' | error { error("missing ')'"); } ; optional_semi: /* lambda */ | ';' ; unsigned_number: INT_CONST | REAL_CONST ; %% __inline__ void *xmalloc(size_t sz) { void *ret = malloc(sz); if(ret == NULL) err(-1, "out of memory"); return ret; } __inline__ char *xstrdup(char *b) { char *ret = strdup(b); if(ret == NULL) err(-1, "out of memory"); return ret; } __inline__ void *xrealloc(void *p, size_t sz) { void *ret = realloc(p, sz); if(ret == NULL) err(-1, "out of memory"); return ret; } __inline__ tnode *talloc(void) { tnode *t = (tnode *) xmalloc(sizeof(tnode)); memset(t, 0x0, sizeof(tnode)); return t; } __inline__ void xfree(void *p) { if(p != NULL) { free(p); return; } err(-1, "NULL ptr passed to xfree()"); } void add_to_locations(tnode *t) { loc *new_loc; new_loc = xmalloc(sizeof(loc)); new_loc->location.line = line_num; new_loc->location.pos = pos_num; new_loc->next = t->locations; t->locations = new_loc; } char *get_locations(tnode *t) { loc *l; char *ret = NULL; char linebuf[10], posbuf[10]; char *p; int tlen = 0; for(l = t->locations; l; l = l->next) { int llen, plen; llen = snprintf(linebuf, sizeof(linebuf), "%d", l->location.line); plen = snprintf(posbuf, sizeof(linebuf), "%d", l->location.pos); ret = xrealloc(ret, llen + plen + 3); p = ret + tlen; memcpy(p, linebuf, llen); p += llen; *p++ = ':'; memcpy(p, posbuf, plen); p += plen; *p++ = ' '; *p = '\0'; tlen = p - ret; } return ret; } void tree_add(tnode **t, char *s) { int32_t lex = 0; if(*t == NULL) { *t = talloc(); (*t)->name = xstrdup(s); (*t)->type = 0; (*t)->count = 1; add_to_locations(*t); } else if ((lex = strcmp(s, (*t)->name)) == 0) { (*t)->count++; add_to_locations(*t); } else if (lex > 0) tree_add(&(*t)->right, s); else tree_add(&(*t)->left, s); } void tree_print(tnode *t) { if(t) { char *l = NULL; tree_print(t->left); l = get_locations(t); printf("%-20s : type: %5d, count: %5d, loc: %s\n", t->name, t->type, t->count, l); xfree(l); tree_print(t->right); } } /* main */ int main (int argc, char **argv) { int ret; ret = yyparse(); fprintf(stderr, "parsing %ssuccessful\n", ret ? "un" : ""); tree_print(symtable); return ret; } /* simple warning */ void warning(char *s) { fprintf(stderr, "line %d: %s\n", line_num, s); } /* error routine */ void yyerror(char *s) { fprintf(stderr, "line %d: %s (near '%s') \n", line_num, s, yytext); } /* vi:set ts=8 sts=4 sw=4 tw=79: */