/* File: expandlabel.y * * This file is part of XSCHEM, * a schematic capture and Spice/Vhdl/Verilog netlisting tool for circuit * simulation. * Copyright (C) 1998-2021 Stefan Frederik Schippers * * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* label parser */ %{ #include #include #include #include #ifndef STRINGPTR #define STRINGPTR typedef struct /* used in expandlabel.y */ { char *str; /* label name */ int m; /* label multiplicity, number of wires */ } Stringptr; #endif #define YYERROR_VERBOSE #define SIGN(x) ( (x) < 0 ? -1: 1 ) #define INITIALIDXSIZE 8 extern Stringptr dest_string; /* 20140108 */ static int idxsize=INITIALIDXSIZE; extern int yylex(); extern FILE *errfp; extern void *my_malloc(int id, size_t size); extern void my_free(int id, void *ptr); extern void my_realloc(int id, void *ptr,size_t size); extern size_t my_strdup(int id, char **dest, const char *src); extern int debug_var; extern void dbg(int level, char *fmt, ...); extern int my_snprintf(char *str, int size, const char *fmt, ...); extern int yyparse_error; static void yyerror (const char *s) /* Called by yyparse on error */ { if(yyparse_error == 0 ) yyparse_error = 1; dbg(0, "yyerror(): yyparse():%s\n", s); } static char *expandlabel_strdup(char *src) { char *ptr; if(src==NULL || src[0]=='\0') { ptr=NULL; my_strdup(121, &ptr,""); return ptr; } else { ptr=NULL; my_strdup(122, &ptr,src); dbg(3, "expandlabel_strdup(): duplicated %lu string %s\n",(unsigned long)ptr,src); return ptr; } } static char *expandlabel_strcat(char *s1, char *s2) /* concatenates s1 and s2, with c in between */ { int l1=0,l2=0; char *res; if(s1) l1=strlen(s1); if(s2) l2=strlen(s2); res=my_malloc(730, l1+l2+1); /* 2 strings plus '\0' */ if(s1) memcpy(res, s1, l1); if(s2) memcpy(res + l1 , s2, l2+1); else memcpy(res + l1 , "", 1); return res; } static char *expandlabel_strcat_char(char *s1, char c, char *s2) /* concatenates s1 and s2, with c in between */ { int l1=0,l2=0; char *res; if(s1) l1=strlen(s1); if(s2) l2=strlen(s2); res=my_malloc(123, l1+l2+2); /* 2 strings plus 'c' and '\0' */ if(s1) memcpy(res, s1, l1); res[l1] = c; if(s2) memcpy(res + l1 + 1, s2, l2+1); else memcpy(res + l1 + 1, "", 1); return res; } /* */ /* example: */ /* if n==3 and s="a,b,c" return "a,a,a,b,b,b,c,c,c" */ /* */ static char *expandlabel_strmult2(int n, char *s) /* if n==0 returns "\0" */ { register int i, len; register char *pos,*prev; char *str, *ss; dbg(3, "expandlabel_strmult2(): n=%d s=%s\n", n, s); if(n==0) return expandlabel_strdup(""); len=strlen(s); prev=s; ss = str=my_malloc(124, (len+1)*n); str[0]='\0'; for(pos=s;pos<=s+len;pos++) { if(*pos==',' || *pos=='\0') { for(i=0;i=idxsize) { idxsize*=2; dbg(3, "check_idx(): reallocating idx array: size=%d\n",idxsize); my_realloc(128, ptr, idxsize*sizeof(int)); } } static char *expandlabel_strbus_nobracket(char *s, int *n) { int i,l; int tmplen; char *res=NULL; char *tmp=NULL; my_realloc(107, &res, n[0]*(strlen(s)+20)); my_realloc(108, &tmp, strlen(s)+30); l=0; for(i=1;i B_NUM %token B_CAR %token B_IDXNUM %token B_DOUBLEDOT %token B_NAME %token B_LINE /* BISON Declarations: non terminal symbols*/ %type list %type index %type index_nobracket /* operator precedences (bottom = highest) and associativity */ %left B_NAME %left B_DOUBLEDOT %left ':' %left B_CAR %left ',' %left '*' /* Grammar follows */ %% line: /* empty */ | list { my_strdup(129, &(dest_string.str),$1.str); my_free(737, &$1.str); dest_string.m=$1.m; } ; list: B_NAME { dbg(3, "yyparse(): B_NAME, $1=%s\n", $1); $$.str = expandlabel_strdup($1); my_free(738, &$1); $$.m = 1; } | B_LINE { dbg(3, "yyparse(): B_LINE\n"); $$.str = expandlabel_strdup($1); /* prima era =$1 */ my_free(739, &$1); $$.m = 1; } | list B_NAME { dbg(3, "yyparse(): list B_NAME, $2=%s\n", $2); $$.str = expandlabel_strcat($1.str, $2); my_free(1208, &$1.str); my_free(452, &$2); $$.m = $1.m; } | list '*' B_NUM { dbg(3, "yyparse(): list * B_NUM\n"); dbg(3, "yyparse(): |%s| %d \n",$1.str,$3); $$.str=expandlabel_strmult2($3,$1.str); dbg(3, "yyparse(): |%s|\n",$$.str); $$.m = $3 * $1.m; my_free(740, &$1.str); } | B_NUM '*' list { dbg(3, "yyparse(): B_NUM * list\n"); $$.str=expandlabel_strmult($1,$3.str); $$.m = $1 * $3.m; my_free(741, &$3.str); } | B_NAME '*' list { dbg(3, "yyparse(): B_NAME * list\n"); $$.str=expandlabel_strcat_char($1, '*', $3.str); $$.m = 1; my_free(883, &$1); my_free(158, &$3.str); } | list ',' list { dbg(3, "yyparse(): list , list\n"); $$.str=expandlabel_strcat_char($1.str, ',', $3.str); $$.m = $1.m + $3.m; my_free(742, &$1.str); my_free(743, &$3.str); } | list B_CAR list { dbg(3, "yyparse(): list B_CAR list\n"); $$.str=expandlabel_strcat_char($1.str, $2, $3.str); $$.m = $1.m + $3.m; my_free(744, &$1.str); my_free(745, &$3.str); } | '(' list ')' { dbg(3, "yyparse(): ( list )\n"); $$=$2; } | B_NAME '[' B_NAME ']' { int size = strlen($1) + strlen($3) + 3; $$.str = my_malloc(81, size); $$.m=-1; my_snprintf($$.str, size, "%s[%s]", $1, $3); my_free(746, &$1); my_free(747, &$3); } | B_NAME '[' index ']' { dbg(3, "yyparse(): making bus: n=%d\n",$3[0]); dbg(3, "yyparse(): B_NAME[ index ] , $1=%s $3=%d\n", $1, *$3); $$.str=expandlabel_strbus($1,$3); my_free(748, &$1); dbg(3, "yyparse(): done making bus: n=%d\n",$3[0]); $$.m=$3[0]; my_free(749, &$3); idxsize=INITIALIDXSIZE; } | B_NAME '[' index_nobracket ']' { dbg(3, "yyparse(): making nobracket bus: n=%d\n",$3[0]); $$.str=expandlabel_strbus_nobracket($1,$3); my_free(750, &$1); dbg(3, "yyparse(): done making nobracket bus: n=%d\n",$3[0]); $$.m=$3[0]; my_free(751, &$3); idxsize=INITIALIDXSIZE; } ; index: B_IDXNUM ':' B_IDXNUM ':' B_IDXNUM { int i; int sign; sign = SIGN($3-$1); $$=my_malloc(130, INITIALIDXSIZE*sizeof(int)); $$[0]=0; dbg(3, "yyparse(): parsing first idx range\n"); for(i=$1;;i+=sign*$5) { check_idx(&$$,++$$[0]); $$[$$[0]]=i; if(sign==1 && i>=$3) break; if(sign==-1 && i<=$3) break; } } | B_IDXNUM ':' B_IDXNUM { int i; $$=my_malloc(131, INITIALIDXSIZE*sizeof(int)); $$[0]=0; dbg(3, "yyparse(): parsing first idx range\n"); for(i=$1;;i+=SIGN($3-$1)) { check_idx(&$$,++$$[0]); $$[$$[0]]=i; if(i==$3) break; } } | B_IDXNUM { dbg(3, "yyparse(): parsing first idx item\n"); $$=my_malloc(132, INITIALIDXSIZE*sizeof(int)); $$[0]=0; check_idx(&$$, ++$$[0]); $$[$$[0]]=$1; } | index ',' B_IDXNUM ':' B_IDXNUM ':' B_IDXNUM { int i; int sign; sign = SIGN($5-$3); dbg(3, "yyparse(): parsing comma sep idx range\n"); for(i=$3;;i+=sign*$7) { check_idx(&$$, ++$$[0]); $$[$$[0]]=i; if(sign==1 && i>=$5) break; if(sign==-1 && i<=$5) break; } } | index ',' B_IDXNUM ':' B_IDXNUM { int i; dbg(3, "yyparse(): parsing comma sep idx range\n"); for(i=$3;;i+=SIGN($5-$3)) { check_idx(&$$, ++$$[0]); $$[$$[0]]=i; if(i==$5) break; } } | index ',' B_IDXNUM { dbg(3, "yyparse(): parsing comma sep idx list\n"); check_idx(&$$, ++$$[0]); $$[$$[0]]=$3; } ; index_nobracket: B_IDXNUM B_DOUBLEDOT B_IDXNUM { int i; $$=my_malloc(85, INITIALIDXSIZE*sizeof(int)); $$[0]=0; dbg(3, "yyparse(): doubledot\n"); for(i=$1;;i+=SIGN($3-$1)) { check_idx(&$$,++$$[0]); $$[$$[0]]=i; if(i==$3) break; } } | B_IDXNUM B_DOUBLEDOT B_IDXNUM B_DOUBLEDOT B_IDXNUM { int i; int sign; sign = SIGN($3-$1); $$=my_malloc(109, INITIALIDXSIZE*sizeof(int)); $$[0]=0; dbg(3, "yyparse(): parsing first idx range\n"); for(i=$1;;i+=sign*$5) { check_idx(&$$,++$$[0]); $$[$$[0]]=i; if(sign==1 && i>=$3) break; if(sign==-1 && i<=$3) break; } } %%