%{#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; } ;
%{
#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; }
;