Subversion Repositories planix.SVN

Rev

Blame | Last modification | View Log | RSS feed

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