
/*
 * hdl.y parser for verilog net lists 
 *  by  Frank Bennett 
 *
 * i.e. hdl s.g 
 * products two files: s.nam, s.seq - 1 net per line
 *   s.seq is sorted by reference designator
 *   s.nam is sorted by netname
 *
 * - primarily handles "flat" verilog HDL netlists.
 * - parses hierarchical netlist but currently doesn't flatten them.
 * - concatenated signal names need to be expanded. currently the whole
 *   netname bundle is given the name : "concatenation"
 * - not included :
 * 	Behavioral Statements
 *	Specify blocks
 *
 *  PD yacc :
 * byacc, Bob Corbett. Berkely yacc adapted for MINIX by Peter Housel
 * COLOGNE:commands/lex-yacc/byacc.tar.Z
 *
 * DOS extender - 386 to avoid malloc problems
 * djgpp.zip 
 * wuarchive.wustl.edu   (128.252.135.4): /mirrors3/garbo.uwasa.fi/programming
 */
%{
#define YYDEBUG 1
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>

#define out(c) putc(c,yyout)
#define NCOM 300

int	bug=0, ind ;
FILE 	*fopen(), *freopen(), *fi, *ft, *fo, *fr ;
static 	int i, comment=0;
char  	*cp, *st, refd[20], part[20] ;
char	ln[80] ;

extern char 	*strsave(), *malloc();
extern int	yyleng, lexval ;
extern char	yytext[];
extern char	yysbuf[];

typedef struct YYS_TYPE { /* use instead of %union below */
    int i;
    char s[50];
    } yys_type ;
#define YYSTYPE     yys_type


# define YYLMAX 132

int	yylineno =0;
int	yyleng ;
char	yytext[YYLMAX];
char	yysbuf[YYLMAX];
char 	modnam[YYLMAX];
int 	yysptr = -1, yylast, toklast;
FILE	*yyout;
#define YYNL 10


%}

/* HP-UX yacc seems to be fussy about :
%union {
    int i;
    char s[50];
    }
 */

%token NL NAME NUMBER MODULE ENDMODULE WIRE INPUT OUTPUT INOUT
%token NETTYPE ASSIGN STRENGTH0 STRENGTH1 GATETYPE INITIAL
%token PARAMETER REG TIME INTEGER REAL EVENT DEFPARAM
%token BIN_OP UNARY_OP PRIMITIVE ENDPRIM TABLE ENDTABLE
%token OUT_SYM LEV_SYM EDGE_SYM

%left BIN_OP

%start modules

%%
modules 	: modules mod_prim
		| modules         error
		|      	  mod_prim
		;

mod_prim	: module
		| primitive
		;

primitive	: PRIMITIVE NAME '(' list_of_vars ')' ';' prim_body ENDPRIM
		;

list_of_vars	: list_of_vars ',' NAME
		| NAME
		;

prim_body	: UDP_decl UDP_init table_def
		| UDP_decl          table_def
		;

UDP_decl	: output_decl
		| input_decl
		| reg_decl
		;

UDP_init	: INITIAL NAME '=' init_val
		;

init_val	: '1' '\'' 'b' '0'
		| '1' '\'' 'b' '1'
		| '1' '\'' 'b' 'x'
		| '1'
		| '0'
		;

table_def	: TABLE table_entries ENDTABLE
		;

table_entries	: table_entries combin_entry
		|               combin_entry
		| table_entries seq_entry
		|               seq_entry
		;

combin_entry	: level_in_list ':' OUT_SYM ';'
		;

seq_entry	: level_in_list ':' state ':' next_state ';'
		|  edge_in_list ':' state ':' next_state ';'
		;

level_in_list 	: LEV_SYM
		;

edge_in_list	: LEV_SYM edge LEV_SYM
		|         edge
		;

edge		: '(' LEV_SYM LEV_SYM ')'
		| EDGE_SYM
		;

state		: LEV_SYM
		;
next_state	: OUT_SYM
		;

module		: MODULE NAME ';' mod_body ENDMODULE 
      	 	| MODULE NAME '('list_of_ports')' ';' mod_body ENDMODULE 
		;

list_of_ports	: list_of_ports ',' port
		| port
		;

port		: NAME
		| NAME '[' const_exp ']'
		| NAME '[' const_exp ':' const_exp ']'
		;

mod_body	: mod_body module_item 
		|          module_item 
		;

module_item	: param_decl
		| input_decl
		| output_decl
		| inout_decl
		| net_decl
		| reg_decl
		| time_decl
		| integer_decl
		| real_decl
		| event_decl
		| gate_decl
		| module_instant
		| defparm_decl
		| cont_assign
		;

param_decl	: PARAMETER
		;
reg_decl	: REG
		;
time_decl	: TIME
		;
integer_decl	: INTEGER
		;
real_decl	: REAL
		;
event_decl	: EVENT
		;
defparm_decl	: DEFPARAM
		;
gate_decl	: GATETYPE                   gate_instant
		| GATETYPE dr_strength       gate_instant
		| GATETYPE             delay gate_instant
		| GATETYPE dr_strength delay gate_instant
		;

gate_instant	: NAME '(' exp ')'
		;

input_decl	: INPUT       list_vars ';'
		| INPUT range list_vars ';'
		;

output_decl	: OUTPUT       list_vars ';'
		| OUTPUT range list_vars ';'
		;

inout_decl	: INOUT       list_vars ';'
		| INOUT range list_vars ';'
		;

net_decl	: NETTYPE             list_vars ';'
		| NETTYPE range       list_vars ';'
		| NETTYPE       delay list_vars ';'
		| NETTYPE range delay list_vars ';'
		;

range		: '[' const_exp ':' const_exp ']' 
		;

delay		: '#' number
		| '#' NAME
		;

dr_strength	: '(' STRENGTH0 ',' STRENGTH1 ')'
		| '(' STRENGTH1 ',' STRENGTH0 ')'
		;

list_vars	: list_vars ',' NAME
		|               NAME
		;

module_instant	: name_mod         mod_inst_list ';' 
              	| name_mod par_val mod_inst_list ';' 
		;

name_mod	: NAME
		{ strcpy( part, yytext); }
		;

mod_inst_list	: mod_inst_list ',' mod_inst
		|                   mod_inst
		;

mod_inst	: reference '(' list_mod_conn ')'
        	| reference '(' list_nam_conn ')'
		;

reference	: NAME
		{ strcpy( refd, yytext); }
		;

list_mod_conn	: list_mod_conn ',' exp
		|                   exp
		;
 
list_nam_conn	: list_nam_conn ',' nam_conn
		|                   nam_conn
		;
 
nam_conn	: '.' NAME '(' sig_nam ')'
		{
		    fprintf(fo,"%-18s %-22s %-10s %10s %s\n",
			 $4.s, refd, $2.s, part, modnam);
		}
		;

sig_nam		: NAME
		| NAME '[' exp ']'
		{ strcpy($$.s, $1.s);
		  strcat($$.s, "[");
		  strcat($$.s, $3.s);
		  strcat($$.s, "]");
		}
		| NAME '[' exp ':' exp ']'
		{ strcpy($$.s, $1.s);
		  strcat($$.s, "[");
		  strcat($$.s, $3.s);
		  strcat($$.s, ":");
		  strcat($$.s, $5.s);
		  strcat($$.s, "]");
		}
		| concatenation
		{ strcpy($$.s, "concatenation");}
		;

par_val		: '#' '(' exp ')' 
		;

cont_assign	: ASSIGN                   list_assigns ';'
		| ASSIGN dr_strength       list_assigns ';'
		| ASSIGN             delay list_assigns ';'
		| ASSIGN dr_strength delay list_assigns ';'
		;

list_assigns	: list_assigns ',' assignment
		|                  assignment
		;

assignment	: lvalue '='     exp
		| lvalue '=' '(' exp ')'
		;

lvalue		: NAME
		| NAME '[' exp ']'
		| concatenation
		;

const_exp	: exp
		;

concatenation	: '{' exp_list '}'
		;

exp_list	: exp_list ',' exp
		|              exp
		;
	 
exp		: primary
		| UNARY_OP primary
		| UNARY_OP '(' exp ')'
		| exp BIN_OP exp
		;

primary		: number
		| NAME '[' exp ']'
		| NAME
		| concatenation
		;

number		: NUMBER
		| NUMBER '\'' 'b' NUMBER
		| NUMBER '\'' 'd' NUMBER
		| NUMBER '\'' 'o' NUMBER
		;

%%	/* start of main */

main(argc,argv)
int	argc;
char	*argv[];
{
    int	i,p;
    char frnam[60], fsnam[60];
    yyout =stderr;


    if(argc == 1) {
	fprintf(stderr,"use:hdl [-ds] file\n"); exit(1);
    }
    for(i=1; i<argc; i++)
    	if(argv[i][0] == '-'){
		bug     = ((argv[i][1] == 'd') || (argv[i][2] == 'd'));
	}
	else break;


    if(freopen( argv[i],"r",stdin) == NULL){
	fprintf(stderr,"can't open %s\n", argv[i]);exit(1);
    }	else {
	/* open output */
	for( cp=argv[i], st=fsnam ; *cp && *cp != '.' ; )*st++ = *cp++;
	*st = 0;
	strcpy( frnam, fsnam );	
	strcat( frnam, ".nam");	strcat( fsnam, ".seq");

	if((fo = fopen(fsnam, "w")) == NULL) err("can't open %s",fsnam);

	fprintf(stderr,"reading nets from %s\n", argv[i]);
    }

    yyparse() ;
	
    fclose(fo);

    fprintf(stderr,"sorting...\n");
    sprintf(ln, "sort <%s >%s", fsnam, frnam);	system(ln);
}


int 
yylex() /* Gets the next token from the input stream */
{
	int  c, i, j ;
	static int eline ; 
	extern int bug;

start:
	if(yysptr == -1){
		i = 0;	eline =1; yylineno++;
		/* get line to yysbuf */
		while( ((c=getchar()) != EOF) && (c != YYNL)){
			if(c == '\t'){ c=' ';do yysbuf[i++] = c; while(i & 7);}
			else	{
				if (c != ' ')eline =0;	
				yysbuf[i++] = c;
			}
		}
		yysptr = 0;
		yysbuf[i] = '\0';
		yylast = toklast = 0;
	}
	if(c == EOF) 
	    return(EOF);

	while( (c = yysbuf[yysptr]) == ' ') yysptr++;

	if(bug){
		fprintf(yyout,"%03d:%s\n",yylineno,yysbuf);
		for( i=yysptr ; i>0 ; i-- )out(' ');
	}

	 if ( c == YYNL || c== 0 ){ 
		yysptr= -1;
		if(bug)fprintf(yyout,"\n");
		goto start;
	 } 

	 if( comment ){
		while( (c = yysbuf[yysptr++]) != '*' && c != '/'&& c );
		if( c == '*' && yysbuf[yysptr]=='/' )
		    comment-- ;
	        if( c == '/' && yysbuf[yysptr]=='*' )
		    comment++ ;
		if( c ==  0  )
		    yysptr = -1;
		if( comment )
		    goto start;
		yysptr++;
		    goto start;
	 }

	 if( c == '/' ) { /* comment // ? */
	     if( yysbuf[yysptr+1] == '/') {
	     	yysptr= -1;
	     	goto start;
	     }
	     if( yysbuf[yysptr+1] == '*') {
		comment++; yysptr +=2;
		goto start;
	     }
	 }
	 if( c == '\\'){ /* escaped name */
 		yyleng=0;
	        while( (c=yysbuf[++yysptr]) != ' ' ) 
	                yytext[yyleng++] = c;
		yytext[yyleng] = '\0'; 
	        if(bug)fprintf(yyout,"    ^tok:NAME\n");
		if( toklast==MODULE ){
		    toklast = 0;
		    strcpy(modnam, yytext);
		    fprintf(stderr,"module %s\n", modnam);
		}
		if( toklast==PRIMITIVE ){
		    toklast = 0;
		    strcpy(modnam, yytext);
		    fprintf(stderr,"primitive %s\n", modnam);
		}
		strcpy(yylval.s, yytext);
		return(NAME);
	 }
	 if( isalpha(c) ) {
		if( yylast == '\'' ){ /* number base - 1'b0 */
		    yysptr++;
	 	    if(bug)
         	       if(c < ' ')   fprintf(yyout,"    ^CHAR:%d\n",c);
			      else   fprintf(yyout,"    ^CHAR:%c\n",c);
	            yylast = c;
	            return(c);
		}
		if( (j=chktok()) != 0){
		    toklast = j; 
		    return(j);
		}
        name:
 		yyleng=0;
	        while( isalpha(c) || isdigit(c) || c=='_' ) {
	                yytext[yyleng++] = c; c = yysbuf[++yysptr];
       		}
		yytext[yyleng] = '\0'; 
	        if(bug)fprintf(yyout,"    ^tok:NAME\n");
		if( toklast==MODULE ){
		    toklast = 0;
		    strcpy(modnam, yytext);
		    fprintf(stderr,"module %s\n", modnam);
		}
		if( toklast==PRIMITIVE ){
		    toklast = 0;
		    strcpy(modnam, yytext);
		    fprintf(stderr,"primitive %s\n", modnam);
		}
		strcpy(yylval.s, yytext);
		return(NAME);
	 } 
	 if( isdigit(c) ) {
 		yyleng=0;
	        while( isdigit(c) ) {
	                yytext[yyleng++] = c; c = yysbuf[++yysptr];
       		}
		yytext[yyleng] = '\0'; 
	        if(bug)fprintf(yyout,"    ^tok:NUMBER\n");
		strcpy(yylval.s, yytext);
		return(NUMBER);
	 }
	 yysptr++; yylast = c;
	 if( c=='+' || c=='-' || c=='&' || c=='|' || c=='^' ){
	     if(bug) fprintf(yyout,"    ^BIN_OP:%c\n",c);
	     return(BIN_OP);
	 }
	 if( c=='!' || c=='~' ){
	     if(bug) fprintf(yyout,"    ^UNARY_OP:%c\n",c);
	     return(UNARY_OP);
	 }
	 if(bug)
	     if(c < ' ')
		fprintf(yyout,"    ^CHAR:%d\n",c);
	     else
		fprintf(yyout,"    ^CHAR:%c\n",c);
	 return(c);
} /* nexttoken */

int chktok()
{
    static struct { char *keyword; int val, tok; } key [] = {
	"module " ,   0, MODULE,
	"endmodule" , 0, ENDMODULE, 
	"primitive ", 0, PRIMITIVE,
	"endprimitive",0,ENDPRIM,
	"input "    , 0, INPUT,
	"output "   , 0, OUTPUT,
	"inout "    , 0, INOUT,
	"assign "   , 0, ASSIGN,
	"wire "     , 0, NETTYPE,
	"triand "   , 1, NETTYPE,
	"trior "    , 2, NETTYPE,
	"tri1 "     , 3, NETTYPE,
	"tri "      , 4, NETTYPE,
	"supply0 "  , 5, NETTYPE,
	"supply1 "  , 6, NETTYPE,
	"wor "      , 7, NETTYPE,
	"trireg "   , 8, NETTYPE,
	"supply0 "  , 0, STRENGTH0,
	"strong0 "  , 1, STRENGTH0,
	"pull0 "    , 2, STRENGTH0,
	"weak0 "    , 3, STRENGTH0,
	"highz0 "   , 4, STRENGTH0,
	"supply1 "  , 0, STRENGTH1,
	"strong1 "  , 1, STRENGTH1,
	"pull1 "    , 2, STRENGTH1,
	"weak1 "    , 3, STRENGTH1,
	"highz1 "   , 4, STRENGTH1,
	"parameter ", 0, PARAMETER,
	"reg "	    , 0, REG,
	"time "	    , 0, TIME,
	"integer "  , 0, INTEGER,
	"real "     , 0, REAL,
	"event "    , 0, EVENT,
	"defparam " , 0, DEFPARAM,
	"and "	    , 0, GATETYPE,
	"nand "     , 1, GATETYPE,
	"or " 	    , 2, GATETYPE,
	"nor "      , 3, GATETYPE,
	"xor "	    , 4, GATETYPE,
	"xnor "     , 5, GATETYPE,
	"buf "	    , 6, GATETYPE,
	"tran "     , 7, GATETYPE,
	"table "    , 0, TABLE,
	"endtable"  , 0, ENDTABLE,
	"initial "  , 0, INITIAL,
	NULL, 0, 0
	};
    int	save, i, j ;
    char	*s; 

    for( j=0 ; (s=key[j].keyword) != NULL ; j++) {
	save = yysptr; yyleng = 0;
	while( *s == yysbuf[yysptr++] && *s )
	    yytext[yyleng++] = *s++;
	if(*s == '\0'){
	    yytext[yyleng] = '\0';
	    yysptr--;
	    if(bug){
		for( i=yysptr-1 ; i>0 ; i-- )out(' ');
		fprintf(yyout,"    ^tok:%s\n",yytext);
	    }
	    yylval.i = key[j].val;
	    return(key[j].tok);
        }
        yysptr = save;
    }
    return(0);
}

yyerror(s)
char	*s;
{
    int  i;

    fprintf(stderr,"%s error on line %d\n",s,yylineno);
    fprintf(stderr,"%s\n", yysbuf);
    for( i=yysptr ; i>0 ; i-- )out(' ');
    fprintf(stderr,"^\n");
}

char *strsave(s)
char *s;
{
    char *p, *malloc();

    if((p = malloc(strlen(s)+1)) != NULL) strcpy(p,s);
    if( p==NULL)err("out of malloc space");
    return(p);
}

err(s,t)
char *s,*t;
{
    fprintf(stderr,s,t); fprintf(stderr,"\n");
    exit(1);
}