diff options
Diffstat (limited to 'src/cmd/grap/grap.y')
-rw-r--r-- | src/cmd/grap/grap.y | 396 |
1 files changed, 396 insertions, 0 deletions
diff --git a/src/cmd/grap/grap.y b/src/cmd/grap/grap.y new file mode 100644 index 00000000..6d96b2f1 --- /dev/null +++ b/src/cmd/grap/grap.y @@ -0,0 +1,396 @@ +%{ +#include <stdio.h> +#include <math.h> +#include <stdlib.h> +#include <string.h> +#include "grap.h" + +//#define RAND_MAX 32767 /* if your rand() returns bigger, change this too */ + +extern int yylex(void); +extern int yyparse(void); + +%} + +%token <i> FRAME TICKS GRID LABEL COORD +%token <i> LINE ARROW CIRCLE DRAW NEW PLOT NEXT +%token <p> PIC +%token <i> COPY THRU UNTIL +%token <i> FOR FROM TO BY AT WITH +%token <i> IF +%token <p> GRAPH THEN ELSE DOSTR +%token <i> DOT DASH INVIS SOLID +%token <i> TEXT JUST SIZE +%token <i> LOG EXP SIN COS ATAN2 SQRT RAND MAX MIN INT PRINT SPRINTF +%token <i> X Y SIDE IN OUT OFF UP DOWN ACROSS +%token <i> HEIGHT WIDTH RADIUS +%token <f> NUMBER +%token <op> NAME VARNAME DEFNAME +%token <p> STRING +%token <i> ST '(' ')' ',' + +%right <f> '=' +%left <f> OR +%left <f> AND +%nonassoc <f> GT LT LE GE EQ NE +%left <f> '+' '-' +%left <f> '*' '/' '%' +%right <f> UMINUS NOT +%right <f> '^' + +%type <f> expr optexpr if_expr number assign +%type <i> optop +%type <p> optstring if +%type <op> optname iterator name +%type <pt> point +%type <i> side optside numlist comma linetype drawtype +%type <ap> linedesc optdesc stringlist string stringattr sattrlist exprlist +%type <i> frameitem framelist coordlog +%type <f> string_expr + +%% + +top: + graphseq { if (codegen && !synerr) graph((char *) 0); } + | /* empty */ { codegen = 0; } + | error { codegen = 0; ERROR "syntax error" WARNING; } + ; + +graphseq: + statlist + | graph statlist + | graphseq graph statlist + ; +graph: + GRAPH { graph($1); endstat(); } + ; + +statlist: + ST + | stat ST { endstat(); } + | statlist stat ST { endstat(); } + ; + +stat: + FRAME framelist { codegen = 1; } + | ticks { codegen = 1; } + | grid { codegen = 1; } + | label { codegen = 1; } + | coord + | plot { codegen = 1; } + | line { codegen = 1; } + | circle { codegen = 1; } + | draw + | next { codegen = 1; } + | PIC { codegen = 1; pic($1); } + | for + | if + | copy + | numlist { codegen = 1; numlist(); } + | assign + | PRINT expr { fprintf(stderr, "\t%g\n", $2); } + | PRINT string { fprintf(stderr, "\t%s\n", $2->sval); freeattr($2); } + | /* empty */ + ; + +numlist: + number { savenum(0, $1); $$ = 1; } + | numlist number { savenum($1, $2); $$ = $1+1; } + | numlist comma number { savenum($1, $3); $$ = $1+1; } + ; +number: + NUMBER + | '-' NUMBER %prec UMINUS { $$ = -$2; } + | '+' NUMBER %prec UMINUS { $$ = $2; } + ; + +label: + LABEL optside stringlist lablist { label($2, $3); } + ; +lablist: + labattr + | lablist labattr + | /* empty */ + ; +labattr: + UP expr { labelmove($1, $2); } + | DOWN expr { labelmove($1, $2); } + | SIDE expr { labelmove($1, $2); /* LEFT or RIGHT only */ } + | WIDTH expr { labelwid($2); } + ; + +framelist: + framelist frameitem + | /* empty */ { $$ = 0; } + ; +frameitem: + HEIGHT expr { frameht($2); } + | WIDTH expr { framewid($2); } + | side linedesc { frameside($1, $2); } + | linedesc { frameside(0, $1); } + ; +side: + SIDE + ; +optside: + side + | /* empty */ { $$ = 0; } + ; + +linedesc: + linetype optexpr { $$ = makeattr($1, $2, (char *) 0, 0, 0); } + ; +linetype: + DOT | DASH | SOLID | INVIS + ; +optdesc: + linedesc + | /* empty */ { $$ = makeattr(0, 0.0, (char *) 0, 0, 0); } + ; + +ticks: + TICKS tickdesc { ticks(); } + ; +tickdesc: + tickattr + | tickdesc tickattr + ; +tickattr: + side { tickside($1); } + | IN expr { tickdir(IN, $2, 1); } + | OUT expr { tickdir(OUT, $2, 1); } + | IN { tickdir(IN, 0.0, 0); } + | OUT { tickdir(OUT, 0.0, 0); } + | AT optname ticklist { setlist(); ticklist($2, AT); } + | iterator { setlist(); ticklist($1, AT); } + | side OFF { tickoff($1); } + | OFF { tickoff(LEFT|RIGHT|TOP|BOT); } + | labattr + ; +ticklist: + tickpoint + | ticklist comma tickpoint + ; +tickpoint: + expr { savetick($1, (char *) 0); } + | expr string { savetick($1, $2->sval); } + ; +iterator: + FROM optname expr TO optname expr BY optop expr optstring + { iterator($3, $6, $8, $9, $10); $$ = $2; } + | FROM optname expr TO optname expr optstring + { iterator($3, $6, '+', 1.0, $7); $$ = $2; } + ; +optop: + '+' { $$ = '+'; } + | '-' { $$ = '-'; } + | '*' { $$ = '*'; } + | '/' { $$ = '/'; } + | /* empty */ { $$ = ' '; } + ; +optstring: + string { $$ = $1->sval; } + | /* empty */ { $$ = (char *) 0; } + ; + +grid: + GRID griddesc { ticks(); } + ; +griddesc: + gridattr + | griddesc gridattr + ; +gridattr: + side { tickside($1); } + | X { tickside(BOT); } + | Y { tickside(LEFT); } + | linedesc { griddesc($1); } + | AT optname ticklist { setlist(); gridlist($2); } + | iterator { setlist(); gridlist($1); } + | TICKS OFF { gridtickoff(); } + | OFF { gridtickoff(); } + | labattr + ; + +line: + LINE FROM point TO point optdesc { line($1, $3, $5, $6); } + | LINE optdesc FROM point TO point { line($1, $4, $6, $2); } + ; +circle: + CIRCLE RADIUS expr AT point { circle($3, $5); } + | CIRCLE AT point RADIUS expr { circle($5, $3); } + | CIRCLE AT point { circle(0.0, $3); } + ; + +stringlist: + string + | stringlist string { $$ = addattr($1, $2); } + ; +string: + STRING sattrlist { $$ = makesattr($1); } + | SPRINTF '(' STRING ')' sattrlist + { $$ = makesattr(sprntf($3, (Attr*) 0)); } + | SPRINTF '(' STRING ',' exprlist ')' sattrlist + { $$ = makesattr(sprntf($3, $5)); } + ; +exprlist: + expr { $$ = makefattr(NUMBER, $1); } + | exprlist ',' expr { $$ = addattr($1, makefattr(NUMBER, $3)); } + ; +sattrlist: + stringattr + | sattrlist stringattr + | /* empty */ { $$ = (Attr *) 0; } + ; +stringattr: + JUST { setjust($1); } + | SIZE optop expr { setsize($2, $3); } + ; + +coord: + COORD optname coordlist { coord($2); } + | COORD optname { resetcoord($2); } + ; +coordlist: + coorditem + | coordlist coorditem + ; +coorditem: + coordlog { coordlog($1); } + | X point { coord_x($2); } + | Y point { coord_y($2); } + | X optname expr TO expr { coord_x(makepoint($2, $3, $5)); } + | Y optname expr TO expr { coord_y(makepoint($2, $3, $5)); } + | X FROM optname expr TO expr { coord_x(makepoint($3, $4, $6)); } + | Y FROM optname expr TO expr { coord_y(makepoint($3, $4, $6)); } + ; +coordlog: + LOG X { $$ = XFLAG; } + | LOG Y { $$ = YFLAG; } + | LOG X LOG Y { $$ = XFLAG|YFLAG; } + | LOG Y LOG X { $$ = XFLAG|YFLAG; } + | LOG LOG { $$ = XFLAG|YFLAG; } + ; + +plot: + stringlist AT point { plot($1, $3); } + | PLOT stringlist AT point { plot($2, $4); } + | PLOT expr optstring AT point { plotnum($2, $3, $5); } + ; + +draw: + drawtype optname linedesc { drawdesc($1, $2, $3, (char *) 0); } + | drawtype optname optdesc string { drawdesc($1, $2, $3, $4->sval); } + | drawtype optname string optdesc { drawdesc($1, $2, $4, $3->sval); } + ; +drawtype: + DRAW + | NEW + ; + +next: + NEXT optname AT point optdesc { next($2, $4, $5); } + +copy: + COPY copylist { copy(); } + ; +copylist: + copyattr + | copylist copyattr + ; +copyattr: + string { copyfile($1->sval); } + | THRU DEFNAME { copydef($2); } + | UNTIL string { copyuntil($2->sval); } + ; + +for: + FOR name FROM expr TO expr BY optop expr DOSTR + { forloop($2, $4, $6, $8, $9, $10); } + | FOR name FROM expr TO expr DOSTR + { forloop($2, $4, $6, '+', 1.0, $7); } + | FOR name '=' expr TO expr BY optop expr DOSTR + { forloop($2, $4, $6, $8, $9, $10); } + | FOR name '=' expr TO expr DOSTR + { forloop($2, $4, $6, '+', 1.0, $7); } + ; + +if: + IF if_expr THEN ELSE { $$ = ifstat($2, $3, $4); } + | IF if_expr THEN { $$ = ifstat($2, $3, (char *) 0); } + ; +if_expr: + expr + | string_expr + | if_expr AND string_expr { $$ = $1 && $3; } + | if_expr OR string_expr { $$ = $1 || $3; } + ; +string_expr: + STRING EQ STRING { $$ = strcmp($1,$3) == 0; free($1); free($3); } + | STRING NE STRING { $$ = strcmp($1,$3) != 0; free($1); free($3); } + ; + +point: + optname expr comma expr { $$ = makepoint($1, $2, $4); } + | optname '(' expr comma expr ')' { $$ = makepoint($1, $3, $5); } + ; +comma: + ',' { $$ = ','; } + ; + +optname: + NAME { $$ = $1; } + | /* empty */ { $$ = lookup(curr_coord, 1); } + ; + +expr: + NUMBER + | assign + | '(' string_expr ')' { $$ = $2; } + | VARNAME { $$ = getvar($1); } + | expr '+' expr { $$ = $1 + $3; } + | expr '-' expr { $$ = $1 - $3; } + | expr '*' expr { $$ = $1 * $3; } + | expr '/' expr { if ($3 == 0.0) { + ERROR "division by 0" WARNING; $3 = 1; } + $$ = $1 / $3; } + | expr '%' expr { if ((long)$3 == 0) { + ERROR "mod division by 0" WARNING; $3 = 1; } + $$ = (long)$1 % (long)$3; } + | '-' expr %prec UMINUS { $$ = -$2; } + | '+' expr %prec UMINUS { $$ = $2; } + | '(' expr ')' { $$ = $2; } + | LOG '(' expr ')' { $$ = Log10($3); } + | EXP '(' expr ')' { $$ = Exp($3 * log(10.0)); } + | expr '^' expr { $$ = pow($1, $3); } + | SIN '(' expr ')' { $$ = sin($3); } + | COS '(' expr ')' { $$ = cos($3); } + | ATAN2 '(' expr ',' expr ')' { $$ = atan2($3, $5); } + | SQRT '(' expr ')' { $$ = Sqrt($3); } + | RAND '(' ')' { $$ = (double)rand() / (double)RAND_MAX; } + | MAX '(' expr ',' expr ')' { $$ = $3 >= $5 ? $3 : $5; } + | MIN '(' expr ',' expr ')' { $$ = $3 <= $5 ? $3 : $5; } + | INT '(' expr ')' { $$ = (long) $3; } + | expr GT expr { $$ = $1 > $3; } + | expr LT expr { $$ = $1 < $3; } + | expr LE expr { $$ = $1 <= $3; } + | expr GE expr { $$ = $1 >= $3; } + | expr EQ expr { $$ = $1 == $3; } + | expr NE expr { $$ = $1 != $3; } + | expr AND expr { $$ = $1 && $3; } + | expr OR expr { $$ = $1 || $3; } + | NOT expr { $$ = !($2); } + ; +assign: + name '=' expr { $$ = setvar($1, $3); } + ; + +name: + NAME + | VARNAME + ; + +optexpr: + expr + | /* empty */ { $$ = 0.0; } + ; |