// -*-c++-*- // ruri - ruri language compiler // Copyright 2000 Tom Rothamel // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. // This is a program that generates another program. As an exemption, // the output file does not need to be placed under the GPL, provided // that the following paragraph is placed in the generated output. Please // note that this is not an authorization to modify this program to cause // it to output more of itself in order to circumvent my copyright. // // This program contains code Copyright 2000 Tom Rothamel. // It is provided without warranty, and may be redistributed // and used in modified or unmodified form, provided this // copyright notice is retained in the source code. %{ #define YYDEBUG 1 #include "parse.h" void yyerror(char *); int yylex(); %} %union { vector *vs; EXV *exv; Expr *exp; EAdd *ea; Condition *c; SList *sl; Statement *st; string *s; int i; } %token EMIT %token MAIN %token METHOD %token WORD %token CONST %token IN %token OUT %token RETURN %token TRUE %token FALSE %token GOTO %token IF %token ELSE %token WHILE %token FOR %token BREAK %token CONTINUE %token ASM %token HALT %token ERR %token POP %token PUSH %token ALLOCA %token SHL %token EQUALS %token LOGAND %token LOGOR %token NAME %token STRING %token NUMBER %type var_list %type param_list %type statement_list %type statement %type condition %type cond1 %type cond1a %type cond2 %type expr %type expr01 %type expr0 %type eadd_list %type expr1 %type expr11 %type expr2 %type expression_list; %left '+' '-' %% program: EMIT statement { $2->code(); delete $2; } | program EMIT statement { $3->code(); delete $3; } | constants main | program method ; constants: { fprintf(of, ".constant\n"); fprintf(of, "objref 0x14a11\n"); } constant_list { fprintf(of, ".end-constant\n"); } ; constant_list: | constant_list CONST NAME '=' NUMBER ';' { fprintf(of, "%s 0x%X\n", $3->c_str(), $5); delete $3; } ; method: METHOD NAME '(' param_list ')' '{' var_list statement_list '}' { int l; fprintf(of, "\n.method %s(", $2->c_str()); delete $2; l = $4->size(); for (int i = 0; i < l; i++) { if (i) fprintf(of, ", "); fprintf(of, "%s", (*$4)[i].c_str()); } delete $4; fprintf(of, ")\n"); fprintf(of, ".var\n"); l = $7->size(); for(int i = 0; i < l; i++) { fprintf(of, "%s\n", (*$7)[i].c_str()); } fprintf(of, ".end-var\n"); delete $7; $8->code(); delete $8; fprintf(of, ".end-method\n"); } main: MAIN '{' var_list statement_list '}' { int l; fprintf(of, "\n.main\n"); fprintf(of, ".var\n"); l = $3->size(); for(int i = 0; i < l; i++) { fprintf(of, "%s\n", (*$3)[i].c_str()); } fprintf(of, ".end-var\n"); delete $3; $4->code(); delete $4; fprintf(of, ".end-main\n"); } ; param_list: { $$ = new vector; } | WORD NAME { $$ = new vector; $$->push_back(*$2); delete $2; } | param_list ',' WORD NAME { $$ = $1; $$->push_back(*$4); delete $4; }; var_list: { $$ = new vector; } | var_list WORD NAME ';' { $$ = $1; $$->push_back(*$3); delete $3; } ; // Statements //////////////////////////////////////////////////////////////// statement_list: { $$ = new SList(); } | statement_list statement { $$ = $1; $$->add($2); } | statement_list NAME ':' { $$ = $1; $$->add(new SLabel(*$2)); delete $2; } ; statement: GOTO NAME ';' { $$ = new SGoto(*$2); delete $2; } | expr ';' { $$ = new SExprRaw($1); } | OUT expr ';' { $$ = new SOut($2); } | PUSH expr ';' { $$ = new SPush($2); } | RETURN expr ';' { $$ = new SReturn($2); } | BREAK ';' { $$ = new SBreak; } | CONTINUE ';' { $$ = new SContinue; } | '{' statement_list '}' { $$ = $2; } | IF '(' condition ')' statement { $$ = new SIf($3, $5); } | IF '(' condition ')' statement ELSE statement { $$ = new SIfElse($3, $5, $7); } | WHILE '(' condition ')' statement { $$ = new SWhile($3, $5); } | FOR '(' expr ';' condition ';' expr ')' statement { $$ = new SFor($3, $5, $7, $9); } | HALT ';' { $$ = new SAsm("HALT"); } | ERR ';' { $$ = new SAsm("ERR"); } | ASM STRING ';' { $$ = new SAsm(*$2); delete $2; } | OUT STRING ';' { $$ = new SOutString(*$2); delete $2; } ; condition: cond1 { $$ = $1; } | condition LOGOR condition { $$ = new COr($1, $3); } ; cond1: cond1a { $$ = $1; } | cond1 LOGAND cond1 { $$ = new CAnd($1, $3); } ; cond1a: cond2 { $$ = $1; } | '!' cond1a { $$ = new CNot($2); } ; cond2: '(' condition ')' { $$ = $2; } | TRUE { $$ = new CTrue(); } | FALSE { $$ = new CFalse(); } | expr { $$ = new CExpr($1); } | expr '<' expr { $$ = new CLt($1, $3); } | expr '>' expr { $$ = new CGt($1, $3); } | expr EQUALS expr { $$ = new CEq($1, $3); } | expr '!' '=' expr { $$ = new CNot(new CEq($1, $4)); } | expr '<' '=' expr { $$ = new CNot(new CGt($1, $4)); } | expr '>' '=' expr { $$ = new CNot(new CLt($1, $4)); } ; // Expressions /////////////////////////////////////////////////////////////// // Of this, only expr should be used by the rest of the code to represent // an expression. Remember to optimize it before using. expression_list: { $$ = new EXV; $$->push_back(new ENamedConst("OBJREF")); } | expr { $$ = new EXV; $$->push_back(new ENamedConst("OBJREF")); $$->push_back($1); } | expression_list ',' expr { $$ = $1; $$->push_back($3); } ; expr: expr01 { $$ = $1; } | NAME '=' expr { $$ = new EStore(*$1, $3); delete $1; } | expr2 '[' expr ']' '=' expr { $$ = new EAStore($1, $3, $6); } ; expr01: expr0 { $$ = $1; } | POP { $$ = new EPop(); } ; expr0: expr1 { $$ = $1; } | eadd_list { $$ = $1; } | expr0 '-' expr0 { $$ = new ESub($1, $3); } ; eadd_list: expr0 '+' expr0 { $$ = new EAdd($1, $3); } | eadd_list '+' expr0 { $1->addterm($3); $$ = $1; } ; expr1: expr11 { $$ = $1; } | expr1 '*' NUMBER { $$ = new EMul($1, $3); } | expr1 SHL NUMBER { $$ = new EShl($1, $3); } ; expr11: expr2 { $$ = $1; } | expr11 '|' expr11 { $$ = new EOr($1, $3); } | expr11 '&' expr11 { $$ = new EAnd($1, $3); } ; expr2: '(' expr ')' { $$ = $2; } | NAME { $$ = new EFetch(*$1); delete $1; } | CONST NAME { $$ = new ENamedConst(*$2); delete $2; } | NUMBER { if ($1 < 0 || $1 > 255) { yyerror("Numeric constant out of range."); } $$ = new EConst($1); } | NAME '(' expression_list ')' { $$ = new EMethod(*$1, $3); delete $1; } | IN { $$ = new EIn; } | expr2 '[' expr ']' { $$ = new EAFetch($1, $3); } | ALLOCA '(' expr ')' { $$ = new EAlloca($3); } | STRING { $$ = new EAString(*$1); delete $1; } | '~' expr2 { $$ = new ENot($2); } ; %% extern int yylineno; void yyerror(char *err) { fprintf(stderr, "error at line %d: %s\n", yylineno, err); exit(-1); }