
%token K_IF K_FUNC
%token <num> NUM 
%token <sym> SYM
%nonassoc ASSIGN
%left <op> EQOP
%left <op> ADDOP
%left <op> MULOP
%nonassoc '('				/* Ends up being left-associative anyway! */
%type <mark> if_tail
%union {
    void *sym;				/* Really a C++ Symbol */
    void *program;			/* Really a C++ Program (with compiler state) */
    long num;
    int op;
    long mark;
}
%{
#include <stdlib.h>
#include "ops.h"


int yywrap();
int yylook();
int yyerror(char *);

void *CppIntern (char *c);
void *CppNewFunc (void);
void CppDoneFunc (void *);
void CppAddParam (void *);
void CppFetchVar (int, void *);

static long CompAfterPred(void);
static long CompAfterConsequent(long mark);
static void CompAfterIf(long mark, int elsep);
%}

%%

exprseq : expr
	| exprseq { CppAddOp(O_POP); } ',' expr

expr : expr ADDOP expr { CppAddOp($2); }
     | expr MULOP expr { CppAddOp($2); }
     | expr EQOP expr { CppAddOp($2); }
     | lvalue ASSIGN expr { CppAddOp(O_ASSIGN); }

     | '(' expr ')'
     | '{' exprseq '}'

     | NUM { CppAddOp(O_NUM); CppAddL($1); }
     | SYM { CppFetchVar(0, $1); }

     | K_IF expr ',' { $<mark>$ = CompAfterPred(); } 
       expr { $<mark>$ = CompAfterConsequent($<mark>4); }
       if_tail { CompAfterIf ($<mark>6, $7); }

     | expr '(' { CppAddOp(O_MAKEFRAME); } opt_arglist ')' { CppAddOp(O_CALL); }

     | K_FUNC { $<program>$ = CppNewFunc(); } '(' opt_param_list ')' '{' exprseq '}' { CppDoneFunc($<program>2); }

opt_arglist : /* empty */
	    | arglist

arglist : expr { CppAddOp(O_PARAM); }
	| arglist ',' expr { CppAddOp(O_PARAM); }

opt_param_list : /* empty */
	       | param_list

param_list : SYM
	   { CppAddParam ($1); }
	   | param_list ',' SYM
	   { CppAddParam ($3); }

lvalue : SYM
       { CppFetchVar(1, $1); }
       

if_tail : '.'
	{ $$ = 0; }
	| ',' expr '.'
	{ $$ = 1; }


%%

#include "toke.c"

yyerror(char *s)
{
    fprintf (stderr, "parse error: %s\n", s);
}

int yywrap (void)
{
    return 1;
}

static long CompAfterPred(void)
{
    long mark;
    CppAddOp(O_BRANCH);
    mark = CppEndProg();
    CppAddL(-1);				/* Fill in later */
    return mark;
}

static long CompAfterConsequent(long mark)
{
    long mark2;
    CppAddOp(O_GOTO);
    mark2 = CppEndProg();
    CppAddL(-1);
    CppSetL(mark, CppEndProg() - mark);
    return mark2;
}
    
static void CompAfterIf(long mark, int elsep)
{
    if (!elsep) {
	CppAddOp (O_NUM);
	CppAddL (0);
    }
    CppSetL(mark, CppEndProg() - mark);
}
