/* File: expandlabel.y * * This file is part of XSCHEM, * a schematic capture and Spice/Vhdl/Verilog netlisting tool for circuit * simulation. * Copyright (C) 1998-2023 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 #include "xschem.h" static int dbg_var=3; #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 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 size_t my_snprintf(char *str, size_t 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); dbg(0, " schematic: %s\n", xctx->sch[xctx->currsch]); } static char *expandlabel_strdup(char *src) { char *ptr; if(src==NULL || src[0]=='\0') { ptr=NULL; my_strdup(_ALLOC_ID_, &ptr,""); return ptr; } else { ptr=NULL; my_strdup(_ALLOC_ID_, &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 */ { size_t l1=0,l2=0; char *res; if(s1) l1=strlen(s1); if(s2) l2=strlen(s2); res=my_malloc(_ALLOC_ID_, 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 */ { size_t l1=0,l2=0; char *res; if(s1) l1=strlen(s1); if(s2) l2=strlen(s2); res=my_malloc(_ALLOC_ID_, 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; register size_t 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(_ALLOC_ID_, (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(_ALLOC_ID_, 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(_ALLOC_ID_, &res, n[0]*(strlen(s)+20)); my_realloc(_ALLOC_ID_, &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 { dbg(dbg_var, "yyparse(): list, dest_string.str=%s\n", $1.str); my_strdup(_ALLOC_ID_, &(dest_string.str),$1.str); my_free(_ALLOC_ID_, &$1.str); dest_string.m=$1.m; } ; list: B_NAME { dbg(dbg_var, "yyparse(): B_NAME, $1=%s\n", $1); $$.str = expandlabel_strdup($1); my_free(_ALLOC_ID_, &$1); $$.m = 1; } | B_LINE { dbg(dbg_var, "yyparse(): B_LINE\n"); $$.str = expandlabel_strdup($1); /* prima era =$1 */ my_free(_ALLOC_ID_, &$1); $$.m = 1; } | list B_NAME { dbg(dbg_var, "yyparse(): list B_NAME, $2=%s\n", $2); $$.str = expandlabel_strcat($1.str, $2); my_free(_ALLOC_ID_, &$1.str); my_free(_ALLOC_ID_, &$2); $$.m = $1.m; } | list '*' B_NUM { dbg(dbg_var, "yyparse(): list * B_NUM\n"); dbg(dbg_var, "yyparse(): |%s| %d \n",$1.str,$3); $$.str=expandlabel_strmult2($3,$1.str); dbg(dbg_var, "yyparse(): |%s|\n",$$.str); $$.m = $3 * $1.m; my_free(_ALLOC_ID_, &$1.str); } | B_NUM '*' list { dbg(dbg_var, "yyparse(): B_NUM * list\n"); $$.str=expandlabel_strmult($1,$3.str); $$.m = $1 * $3.m; my_free(_ALLOC_ID_, &$3.str); } | list ',' list { dbg(dbg_var, "yyparse(): list , list\n"); $$.str=expandlabel_strcat_char($1.str, ',', $3.str); $$.m = $1.m + $3.m; my_free(_ALLOC_ID_, &$1.str); my_free(_ALLOC_ID_, &$3.str); } | list B_CAR list { dbg(dbg_var, "yyparse(): list B_CAR list\n"); $$.str=expandlabel_strcat_char($1.str, (char)$2, $3.str); $$.m = $1.m + $3.m; my_free(_ALLOC_ID_, &$1.str); my_free(_ALLOC_ID_, &$3.str); } | '(' list ')' { dbg(dbg_var, "yyparse(): ( list )\n"); $$=$2; } | B_NAME '[' B_NAME ']' { size_t size = strlen($1) + strlen($3) + 3; dbg(dbg_var, "yyparse(): B_NAME [ B_NAME ] , $1=%s $3=%s\n", $1, $3); $$.str = my_malloc(_ALLOC_ID_, size); $$.m=-1; my_snprintf($$.str, size, "%s[%s]", $1, $3); my_free(_ALLOC_ID_, &$1); my_free(_ALLOC_ID_, &$3); } | B_NAME '[' index ']' { dbg(dbg_var, "yyparse(): B_NAME [ index ] , $1=%s $3=%d\n", $1, $3[0]); $$.str=expandlabel_strbus($1,$3); my_free(_ALLOC_ID_, &$1); $$.m=$3[0]; my_free(_ALLOC_ID_, &$3); idxsize=INITIALIDXSIZE; } | B_NAME '[' index_nobracket ']' { dbg(dbg_var, "yyparse(): B_NAME [ index_nobracket ] $1=%s $3=%d\n",$1, $3[0]); $$.str=expandlabel_strbus_nobracket($1,$3); my_free(_ALLOC_ID_, &$1); $$.m=$3[0]; my_free(_ALLOC_ID_, &$3); idxsize=INITIALIDXSIZE; } ; index: B_IDXNUM ':' B_IDXNUM ':' B_IDXNUM ':' B_IDXNUM { /* start : end : extend : repetitions */ int r, i, sign, offset; sign = XSIGN($3-$1); $$=my_malloc(_ALLOC_ID_, INITIALIDXSIZE*sizeof(int)); $$[0]=0; offset = 0; for(r=0; r < $7; r++) { for(i = $1;; i += sign) { check_idx(&$$,++$$[0]); $$[$$[0]] = i + offset; if(i == $3) break; } offset += $5; } } | B_IDXNUM ':' B_IDXNUM ':' B_IDXNUM { int i; int sign; sign = XSIGN($3-$1); $$=my_malloc(_ALLOC_ID_, INITIALIDXSIZE*sizeof(int)); $$[0]=0; for(i=$1;;i+=sign*$5) { check_idx(&$$,++$$[0]); $$[$$[0]]=i; if(sign==1 && i + $5 > $3) break; if(sign==-1 && i - $5 < $3) break; } } | B_IDXNUM ':' B_IDXNUM { int i; $$=my_malloc(_ALLOC_ID_, INITIALIDXSIZE*sizeof(int)); $$[0]=0; for(i=$1;;i+=XSIGN($3-$1)) { check_idx(&$$,++$$[0]); $$[$$[0]]=i; if(i==$3) break; } } | B_IDXNUM { $$=my_malloc(_ALLOC_ID_, INITIALIDXSIZE*sizeof(int)); $$[0]=0; check_idx(&$$, ++$$[0]); $$[$$[0]]=$1; } | index ',' B_IDXNUM ':' B_IDXNUM ':' B_IDXNUM ':' B_IDXNUM { /* start : end : extend : repetitions */ int r, i, sign, offset; sign = XSIGN($5-$3); offset = 0; for(r=0; r < $9; r++) { for(i = $3;; i += sign) { check_idx(&$$,++$$[0]); $$[$$[0]] = i + offset; if(i == $5) break; } offset += $7; } } | index ',' B_IDXNUM ':' B_IDXNUM ':' B_IDXNUM { int i; int sign; sign = XSIGN($5-$3); for(i=$3;;i+=sign*$7) { check_idx(&$$, ++$$[0]); $$[$$[0]]=i; if(sign==1 && i + $7 > $5) break; if(sign==-1 && i - $7 < $5) break; } } | index ',' B_IDXNUM ':' B_IDXNUM { int i; for(i=$3;;i+=XSIGN($5-$3)) { check_idx(&$$, ++$$[0]); $$[$$[0]]=i; if(i==$5) break; } } | index ',' B_IDXNUM { check_idx(&$$, ++$$[0]); $$[$$[0]]=$3; } ; index_nobracket: B_IDXNUM B_DOUBLEDOT B_IDXNUM B_DOUBLEDOT B_IDXNUM B_DOUBLEDOT B_IDXNUM { /* start .. end .. offset .. repetitions */ int r, i, sign, offset; sign = XSIGN($3-$1); $$=my_malloc(_ALLOC_ID_, INITIALIDXSIZE*sizeof(int)); $$[0]=0; offset = 0; for(r=0; r < $7; r++) { for(i = $1;; i += sign) { check_idx(&$$,++$$[0]); $$[$$[0]] = i + offset; if(i == $3) break; } offset += $5; } } | B_IDXNUM B_DOUBLEDOT B_IDXNUM B_DOUBLEDOT B_IDXNUM { int i; int sign; sign = XSIGN($3-$1); $$=my_malloc(_ALLOC_ID_, INITIALIDXSIZE*sizeof(int)); $$[0]=0; for(i=$1;;i+=sign*$5) { check_idx(&$$,++$$[0]); $$[$$[0]]=i; if(sign==1 && i + $5 > $3) break; if(sign==-1 && i - $5 < $3) break; } } | B_IDXNUM B_DOUBLEDOT B_IDXNUM { int i; $$=my_malloc(_ALLOC_ID_, INITIALIDXSIZE*sizeof(int)); $$[0]=0; for(i=$1;;i+=XSIGN($3-$1)) { check_idx(&$$,++$$[0]); $$[$$[0]]=i; if(i==$3) break; } } | index_nobracket ',' B_IDXNUM B_DOUBLEDOT B_IDXNUM B_DOUBLEDOT B_IDXNUM B_DOUBLEDOT B_IDXNUM { /* start .. end .. offset .. repetitions */ int r, i, sign, offset; sign = XSIGN($5-$3); offset = 0; for(r=0; r < $9; r++) { for(i = $3;; i += sign) { check_idx(&$$,++$$[0]); $$[$$[0]] = i + offset; if(i == $5) break; } offset += $7; } } | index_nobracket ',' B_IDXNUM B_DOUBLEDOT B_IDXNUM B_DOUBLEDOT B_IDXNUM { int i; int sign; sign = XSIGN($5-$3); for(i=$3;;i+=sign*$7) { check_idx(&$$, ++$$[0]); $$[$$[0]]=i; if(sign==1 && i + $7 > $5) break; if(sign==-1 && i - $7 < $5) break; } } | index_nobracket ',' B_IDXNUM B_DOUBLEDOT B_IDXNUM { int i; for(i=$3;;i+=XSIGN($5-$3)) { check_idx(&$$, ++$$[0]); $$[$$[0]]=i; if(i==$5) break; } } | index_nobracket ',' B_IDXNUM { check_idx(&$$, ++$$[0]); $$[$$[0]]=$3; } %%