/****************************************************************************
    Copyright (C) 1987-2004 by Jeffery P. Hansen

    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.
****************************************************************************/
%token ASSIGN MODULE ENDMODULE INPUT OUTPUT INOUT WIRE VERSION SUPPLY0 SUPPLY1
%token PRIMITIVE TECHNOLOGY DELAY AREA POWER IF ELSE SWITCH CASE RETURN BREAK NEXT FUNC DEFAULT

%token SEMI COLON COMMA DOT ASGN LPAREN RPAREN LBRACE RBRACE LBRACK RBRACK AT
%token ANOTATE ENDANOTATE ROT WPLACE SHOWNAME STATE ENDDECLS NOT PORTS BDPORTS
%token SIZE JOINT COMMENT FRAME SLASH BDESC ROOTMODULE TRAN COMLINE COMEND SCRIPT
%token PROPERTY DECPOS


%token GT LT EQ

%token BOGOCHAR

%token <I> NUMBER
%token <S> HEX VERNUM
%token <S> LITERAL STRING

%type <I> bwidth obang bdir
%type <S> dparm 
%type <E> pexpr pcode pc_stats pc_stat

%left EQ NE
%left OR
%left AND
%left NOT
%left GT LT GE LE
%left ADD SUB
%left MUL DIV
%left POW
%left UNEG

%{
#include <unistd.h>
#include <stdio.h>
#include "config.h"
#include "yybasic.h"
#include "vgrammar.h"
#include "vparser.h"
#include "ycmalloc.h"
#include "delay.h"

static char *tech_name = "default";

void BeginVR();
void BeginAC();
void BeginLC();
void BeginBC();
void BeginDD();
void BeginDDP();
void BeginVN();

%}


%%

prog	:
	| prog punit
	;

punit	: modhead decls enddecl stats ENDMODULE { VerEndModule(); }
	| ANOTATE VERSION STRING ENDANOTATE	{ VerCheckVersion($3); }
	| ANOTATE SCRIPT STRING ENDANOTATE	{ VerAddScript($3); }
	| ANOTATE PROPERTY LITERAL ASGN NUMBER ENDANOTATE { VerCircuitProp($3,&$5,TYPE_INT); }
	| ANOTATE PROPERTY LITERAL ASGN LITERAL ENDANOTATE { VerCircuitProp($3,$5,TYPE_STR); }
	| ANOTATE PROPERTY LITERAL ASGN STRING ENDANOTATE { VerCircuitProp($3,$5,TYPE_STR); }
	| primdef
	| tech_def
	| SEMI
	;

modhead	: MODULE LITERAL LPAREN { VerNewModule($2,0); } omargs RPAREN SEMI
	| MODULE LITERAL SEMI  { VerNewModule($2,1); }
	;

omargs	: 
	| margs
	;


margs	: LITERAL			{ VerModParm($1); }
	| margs COMMA LITERAL		{ VerModParm($3); }
	;

decls	:
	| decls decl
	;

decl	: dtype bwidth LITERAL SEMI 	{ VerNewNet($3,$2); }
	| ANOTATE wnotes ENDANOTATE
	| ANOTATE BDESC { VerBeginBD(); } cnote ENDANOTATE { VerEndBD(); }
	| ANOTATE ROOTMODULE ENDANOTATE { VerSetRootMod(); }
	;

dtype	: INPUT 
	| OUTPUT
	| INOUT
	| WIRE
	| SUPPLY0
	| SUPPLY1
	;

wnotes	:
	| wnotes wnote
	;

wnote	: wend wcoords wend 
	| SHOWNAME COLON NUMBER			{ VerSetShowName($3); }
	| DECPOS COLON NUMBER			{ VerSetWireDecorationPos($3); }
	;

wcoords	: wcoord
	| wcoords wcoord
	;

wcoord	: LPAREN NUMBER COMMA NUMBER RPAREN	{ VerMakeNode($2,$4); }
	;

wend	: LBRACE NUMBER RBRACE			{ VerMakeWire($2); }
	;

enddecl	: ANOTATE ENDDECLS ENDANOTATE		{ VerEndDecls(); }
	;

bwidth	:					{ $$ = 1; }
	| LBRACK NUMBER COLON NUMBER RBRACK	{ $$ = ($2-$4)+1; }
	;

stats	:
	| stats stat
	;

stat	: call { VerEndGate(); }
	| ANOTATE joint ENDANOTATE { VerEndGate(); }
	| ANOTATE iogate ENDANOTATE { VerEndGate(); }
	| ANOTATE comment ENDANOTATE { VerEndGate(); }
	| ANOTATE frame ENDANOTATE { VerEndGate(); }
	| tran { VerEndGate(); }
	| error ENDANOTATE { yyerrok; }
	;

comment	: COMMENT LITERAL { VerGate("comment",$2); } cnote ENDANOTATE
		comlines ANOTATE COMEND
	;

frame	: FRAME LITERAL { VerGate("frame",$2); } cnote
	;

comlines :
	| comlines ANOTATE cnote ENDANOTATE
	;

joint	: JOINT LITERAL { VerGate("joint",$2); } LPAREN LITERAL RPAREN { VerJointNet($5); } cnote
	; 

iogate	: LITERAL LPAREN { VerGate($1,0); } ocargs RPAREN cnote
	| LITERAL LITERAL LPAREN { VerGate($1,$2); } ocargs RPAREN cnote
	;


tran	: TRAN LITERAL LPAREN { VerGate("tran",$2); } carg COMMA 
		tran_arg { VerTranDup(); } RPAREN SEMI ANOTATE cnote ENDANOTATE
	;

tran_arg	: DOT LITERAL LPAREN obang LITERAL tran_range RPAREN { VerAttach($2,$5,$4); }
		| obang LITERAL tran_range			{ VerAttach(0,$2,$1); }
		;

tran_range	: LBRACK NUMBER RBRACK			{ VerTranRange($2,$2); }
		|  LBRACK NUMBER COLON NUMBER RBRACK	{ VerTranRange($2,$4); }
		;


call	: LITERAL LITERAL LPAREN { VerGate($1,$2); }
		ocargs RPAREN SEMI ANOTATE cnote ENDANOTATE
	;

ocargs	: 
	| cargs
	;

cargs	: carg
	| cargs COMMA carg
	;

carg	: DOT LITERAL LPAREN obang LITERAL RPAREN	{ VerAttach($2,$5,$4); }
	| obang LITERAL					{ VerAttach(0,$2,$1); }
	;

obang	:			{ $$ = 0; }
	| NOT			{ $$ = 1; }
	;

cnote	: citem
	| cnote citem
	;

citem	: AT LPAREN NUMBER COMMA NUMBER RPAREN	{ VerSetPos($3,$5); }
	| SIZE COLON LPAREN NUMBER COMMA NUMBER RPAREN { VerSetSize($4,$6); }
	| ROT COLON NUMBER			{ VerSetRot($3); }
	| WPLACE COLON LBRACK wplist RBRACK
	| PORTS COLON LBRACK pplist RBRACK
	| BDPORTS COLON LBRACK bdplist RBRACK
	| SHOWNAME COLON NUMBER			{ VerSetShowName($3); }
	| STATE COLON NUMBER			{ VerSetState($3); }
	| LITERAL COLON NUMBER			{ VerSetProperty($1,$3); }
	| LITERAL COLON STRING			{ VerSetStrProperty($1,$3); }
	| LITERAL COLON LITERAL			{ VerSetStrProperty($1,$3); }
	;

wplist	: 
	| wplist NUMBER				{ VerPlaceWire($2); }
	;

pplist	: 
	| pplist bport
	;

bport	: LITERAL bdir NUMBER			{ VerBlockPort($1,$2,$3); }
	;

bdir	: GT					{ $$ = 2; }
	| LT					{ $$ = 3; }
	| ASGN					{ $$ = 1; }
	;
	
bdplist	: 
	| bdplist bdport
	;

bdport	: LITERAL bdir LITERAL bwidth LPAREN NUMBER SLASH NUMBER RPAREN
			{ VerBDPort($1,$2,$3,$4,$6,$8); }
	;


/******************************************************************************/

tech_def : TECHNOLOGY LITERAL { tech_name = $2; } LBRACE primdefs RBRACE { tech_name = "default"; }
	| TECHNOLOGY DEFAULT LBRACE primdefs RBRACE 
	| VERSION { BeginVN(); } VERNUM { BeginDD(); } 
	;

primdefs :
	 | primdefs primdef
	 | primdefs SEMI
	 ;

primdef	: PRIMITIVE LITERAL { GDelayDef_begin(tech_name,$2); } LBRACE pstats RBRACE { GDelayDef_end(); }
	;

pstats	: 
	| pstats pstat
	;

pstat	: AREA ASGN pexpr SEMI { PrimSet("area",0,$3); }
	| AREA ASGN pcode semi { PrimSet("area",0,$3); }
	| POWER ASGN pexpr SEMI { PrimSet("power",0,$3); }
	| POWER ASGN pcode semi { PrimSet("power",0,$3); }
	| DELAY dparm ASGN pexpr SEMI { PrimSet("delay",$2,$4); }
	| DELAY dparm ASGN pcode semi { PrimSet("delay",$2,$4); }
	;

/*
 * Delay parameter specifier 
 */
dparm	: LT { BeginDDP(); } LITERAL GT {  BeginDD(); $$ = $3; }
	;
	

pexpr	: pexpr ADD pexpr		{ $$ = Expr_op(ADD,$1,$3); }
	| pexpr SUB pexpr		{ $$ = Expr_op(SUB,$1,$3); }
	| pexpr MUL pexpr		{ $$ = Expr_op(MUL,$1,$3); }
	| pexpr DIV pexpr		{ $$ = Expr_op(DIV,$1,$3); }
	| pexpr AND pexpr		{ $$ = Expr_op(AND,$1,$3); }
	| pexpr POW pexpr		{ $$ = Expr_op(POW,$1,$3); }
	| pexpr OR pexpr		{ $$ = Expr_op(OR,$1,$3); }
	| pexpr GT pexpr		{ $$ = Expr_op(GT,$1,$3); }
	| pexpr LT pexpr		{ $$ = Expr_op(LT,$1,$3); }
	| pexpr GE pexpr		{ $$ = Expr_op(GE,$1,$3); }
	| pexpr LE pexpr		{ $$ = Expr_op(LE,$1,$3); }
	| pexpr EQ pexpr		{ $$ = Expr_op(EQ,$1,$3); }
	| pexpr NE pexpr		{ $$ = Expr_op(NE,$1,$3); }
	| NOT pexpr			{ $$ = Expr_op(NOT,0,$2); }
	| SUB pexpr	%prec UNEG	{ $$ = Expr_op(UNEG,0,$2); }
	| LPAREN pexpr RPAREN		{ $$ = $2; }
	| LITERAL LPAREN pexpr RPAREN	{ $$ = Expr_func($1,$3,0); }
	| LITERAL			{ $$ = Expr_lit($1); }
	| NUMBER			{ $$ = Expr_num($1); }
	;

pcode	: LBRACE pc_stats RBRACE	{ $$ = $2; }
	;

pc_stats :				{ $$ = 0; }
	| pc_stats pc_stat		{ $$ = Expr_op(NEXT,$1,$2); }
	;

pc_stat	: LITERAL ASGN pexpr SEMI			{ $$ = Expr_op(ASGN,Expr_lit($1),$3); }
	| IF LPAREN pexpr RPAREN pc_stat		{ $$ = Expr_op3(IF,$3,$5,0); }
	| IF LPAREN pexpr RPAREN pc_stat ELSE pc_stat	{ $$ = Expr_op3(IF,$3,$5,$7); }
	| LBRACE pc_stats RBRACE			{ $$ = $2; }
	| BREAK	SEMI					{ $$ = Expr_op(BREAK,0,0); }
	| CASE NUMBER COLON				{ $$ = Expr_case(CASE,$2); }
	| CASE SUB NUMBER COLON				{ $$ = Expr_case(CASE,-$3); }
	| DEFAULT COLON					{ $$ = Expr_case(DEFAULT,0); }
	| RETURN pexpr SEMI				{ $$ = Expr_op(RETURN,$2,0); }
	| SWITCH LPAREN pexpr RPAREN pc_stat		{ $$ = Expr_op(SWITCH,$3,$5); }
	;

semi	:
	| SEMI
	;

%%
