466 lines
14 KiB
Plaintext
466 lines
14 KiB
Plaintext
/* 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 <ctype.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#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<n;i++) {
|
|
memcpy(ss, prev, pos-prev); /* 20180923 */
|
|
if(i == n - 1 && *pos == '\0') {
|
|
ss[pos - prev] = '\0';
|
|
} else {
|
|
ss[pos - prev] = ',';
|
|
}
|
|
ss += pos-prev+1; /* 20180923 */
|
|
}
|
|
/* if(*pos==',') strcat(str,","); */
|
|
prev=pos+1;
|
|
}
|
|
}
|
|
return str;
|
|
}
|
|
|
|
/* */
|
|
/* example: */
|
|
/* if n==3 and s="a,b,c" return "a,b,c,a,b,c,a,b,c" */
|
|
/* */
|
|
static char *expandlabel_strmult(int n, char *s)
|
|
/* if n==0 returns "\0" */
|
|
{
|
|
register int i, len;
|
|
register char *pos;
|
|
char *str;
|
|
|
|
if(n==0) return expandlabel_strdup("");
|
|
len=strlen(s);
|
|
str=pos=my_malloc(125, (len+1)*n);
|
|
for(i=1;i<=n;i++)
|
|
{
|
|
/* strcpy(pos,s); */
|
|
memcpy(pos, s, len); /* 20180923 */
|
|
pos[len]=',';
|
|
pos+=len+1;
|
|
}
|
|
*(pos-1)='\0';
|
|
return str;
|
|
}
|
|
|
|
static char *expandlabel_strbus(char *s, int *n)
|
|
{
|
|
int i,l;
|
|
int tmplen;
|
|
char *res=NULL;
|
|
char *tmp=NULL;
|
|
my_realloc(126, &res, n[0]*(strlen(s)+20));
|
|
my_realloc(127, &tmp, strlen(s)+30);
|
|
l=0;
|
|
for(i=1;i<n[0];i++)
|
|
{
|
|
tmplen = sprintf(tmp, "%s[%d],", s, n[i]);
|
|
/* strcpy(res+l,tmp); */
|
|
memcpy(res+l,tmp, tmplen+1); /* 20180923 */
|
|
l+=tmplen;
|
|
}
|
|
my_free(735, &tmp);
|
|
sprintf(res+l, "%s[%d]", s, n[i]);
|
|
return res;
|
|
}
|
|
|
|
static void check_idx(int **ptr,int n)
|
|
{
|
|
if(n>=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<n[0];i++)
|
|
{
|
|
tmplen = sprintf(tmp, "%s%d,", s, n[i]);
|
|
/* strcpy(res+l,tmp); */
|
|
memcpy(res+l,tmp, tmplen+1);
|
|
l+=tmplen;
|
|
}
|
|
my_free(736, &tmp);
|
|
sprintf(res+l, "%s%d", s, n[i]);
|
|
return res;
|
|
}
|
|
|
|
%}
|
|
|
|
|
|
%union{
|
|
int val; /* For returning numbers.*/
|
|
Stringptr ptr; /* strings, that is, identifiers */
|
|
char * str;
|
|
int *idx; /* for bus index & bus index ranges */
|
|
}
|
|
|
|
/* BISON Declarations: terminal tokens*/
|
|
%token <val> B_NUM
|
|
%token <val> B_CAR
|
|
%token <val> B_IDXNUM
|
|
%token <val> B_DOUBLEDOT
|
|
%token <str> B_NAME
|
|
%token <str> B_LINE
|
|
/* BISON Declarations: non terminal symbols*/
|
|
%type <ptr> list
|
|
%type <idx> index
|
|
%type <idx> 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;
|
|
}
|
|
}
|
|
|
|
%%
|
|
|