From 1573ea3cad3881c4bcef44573d3391ac50202dce Mon Sep 17 00:00:00 2001 From: stefan schippers Date: Thu, 6 Feb 2025 23:57:01 +0100 Subject: [PATCH] improvements in eval_expr.y, print_spice_element(), translate() to allow multiple expr(...) patterns in strings, they all will be evaluated if possible or returned unevaluated (without `expr(` and `)` ) --- src/eval_expr.y | 107 +++++++++++++++++++++++++++++++++++++++--------- src/token.c | 22 ++++------ 2 files changed, 97 insertions(+), 32 deletions(-) diff --git a/src/eval_expr.y b/src/eval_expr.y index 4fa59958..ba954f26 100644 --- a/src/eval_expr.y +++ b/src/eval_expr.y @@ -10,6 +10,8 @@ static const char *str, *strptr; static char *ret = NULL; +static int dbglev = 1; + /* Data type for links in the chain of functions. */ struct symrec { @@ -29,13 +31,14 @@ static int kklex(); static void kkerror(char *s); static double toint(double x); static void get_expr(double x); +static void get_char(int c); struct fn { char *fname; double (*fnct)(); }; - +static int lex_state = 0; struct fn fn_array[] = { {"int" , toint}, @@ -54,11 +57,14 @@ struct fn fn_array[] %define api.prefix {kk} %union { +int c; double val; /* For returning numbers. */ symrec *tptr; /* For returning symbol-table pointers */ } %token STREND 0 +%token CHAR +%token EXPR /* expr( */ %token NUM /* Simple double precision number */ %token FNCT /* Variable and Function */ %type exp @@ -70,29 +76,45 @@ symrec *tptr; /* For returning symbol-table pointers */ /* Grammar follows */ %% - -line: - | exp STREND {get_expr($1);} - | '\'' exp '\'' STREND {get_expr($2);} +input: + | input line ; -exp: NUM { $$ = $1;} - | FNCT '(' exp ')' { $$ = $1 ? (*($1->fnctptr))($3) : 0.0;} - | exp '+' exp { $$ = $1 + $3; } - | exp '-' exp { $$ = $1 - $3;} - | exp '*' exp { $$ = $1 * $3;} - | exp '%' exp { $$ = (int)$1 % (int)$3;} - | exp '/' exp { $$ = $1 / $3;} - | '-' exp %prec NEG { $$ = -$2;} - | exp '^' exp { $$ = pow ($1, $3);} - | '(' exp ')' { $$ = $2;} +line: + CHAR {get_char($1);} + | EXPR exp ')' {get_expr($2);lex_state = 0;} + | EXPR '\'' exp '\'' ')' {get_expr($3);lex_state = 0;} + | EXPR exp error +; + +exp: NUM {$$ = $1;} + | FNCT '(' exp ')' {$$ = $1 ? (*($1->fnctptr))($3) : 0.0;} + | exp '+' exp {$$ = $1 + $3; } + | exp '-' exp {$$ = $1 - $3;} + | exp '*' exp {$$ = $1 * $3;} + | exp '%' exp {$$ = (int)$1 % (int)$3;} + | exp '/' exp {$$ = $1 / $3;} + | '-' exp %prec NEG {$$ = -$2;} + | exp '^' exp {$$ = pow ($1, $3);} + | '(' exp ')' {$$ = $2;} ; /* End of grammar */ %% +static void get_char(int c) +{ + char s[2]; + dbg(dbglev, "get_char: %c |%s|\n", c, str); + s[0] = (char)c; + s[1] = '\0'; + my_mstrcat(_ALLOC_ID_, &ret, s, NULL); + strptr = str; +} + static void get_expr(double x) { char xx[100]; + dbg(dbglev,"get_expr(): x=%g\n", x); my_snprintf(xx, S(xx), "%.15g", x); my_mstrcat(_ALLOC_ID_, &ret, xx, NULL); strptr = str; @@ -104,10 +126,39 @@ static double toint(double x) return floor(x); } +/* ad=expr(3*xa) pd=expr(2*(3+xa)) --> ad=3*xa pd=2*(3+xa) */ +static void remove_expr(char *s) +{ + char *ptr = s; + int plev = 0; + while(*ptr) { + if(strstr(ptr, "expr(") == ptr) { + ptr += 5; + plev++; + } + if(*ptr == '(') plev++; + if(*ptr == ')') { + plev--; + if(plev == 0) ptr++; + if(!ptr) break; + } + *s = *ptr; + ptr++; + s++; + } + *s = *ptr; +} + + static void kkerror(char *s) /* Called by kkparse on error */ { - /* printf("error: |%s|\n\n |%s|\n", s, strptr); */ - my_mstrcat(_ALLOC_ID_, &ret, strptr, NULL); + char *ss = NULL; + dbg(dbglev, "error: |%s|\n\n |%s|\n", s, str ? str : ""); + my_strdup2(_ALLOC_ID_, &ss, strptr); + remove_expr(ss); + my_mstrcat(_ALLOC_ID_, &ret, ss, NULL); + my_free(_ALLOC_ID_, &ss); + lex_state = 0; } static symrec *getsym(char *sym_name) @@ -155,6 +206,23 @@ static int kklex() int c; if(!str) { return 0; } + if(strstr(str, "expr(") == str) { + lex_state = 1; + str += 5; + dbg(dbglev, "lex(): EXPR\n"); + return EXPR; + } + if(!lex_state) { + c = *str++; + if(c) { + kklval.c = c; + dbg(dbglev, "lex(): CHAR; %c\n", c); + return CHAR; + } else { + dbg(dbglev, "lex(): STREND\n"); + return STREND; + } + } /* Ignore whitespace, get first nonwhite character. */ while ((c = *str++) == ' ' || c == '\t' || c == '\n'); if (c == 0) { @@ -171,7 +239,7 @@ static int kklex() sscanf(str, "%99[.0-9a-zA-Z_]%n", s, &rd); kklval.val = atof_spice(s); str += rd; - /* printf("yylex: NUM: %s\n", s); */ + dbg(dbglev, "lex(): NUM: %s\n", s); return NUM; } /* Char starts an identifier => read the name. */ @@ -192,7 +260,7 @@ static int kklex() symbuf[i] = '\0'; s = getsym (symbuf); kklval.tptr = s; - /* printf("yylex: FNCT=%s\n", symbuf); */ + dbg(dbglev, "ylex: FNCT=%s\n", symbuf); return FNCT; } /* Any other character is a token by itself. */ @@ -201,6 +269,7 @@ static int kklex() char *eval_expr(const char *s) { + lex_state = 0; if(ret) my_free(_ALLOC_ID_, &ret); strptr = str = s; kkparse(); diff --git a/src/token.c b/src/token.c index 12926482..3286ac1d 100644 --- a/src/token.c +++ b/src/token.c @@ -2249,12 +2249,9 @@ int print_spice_element(FILE *fd, int inst) if (!xctx->tok_size) value=get_tok_value(template, token+1, 0); token_exists = xctx->tok_size; - if(strstr(value, "expr(") == value) { - char *ptr; - my_strdup(_ALLOC_ID_, &val, value); - ptr = strrchr(val + 5, ')'); - *ptr = '\0'; - value = eval_expr(translate3(val + 5, 1, xctx->inst[inst].prop_ptr, template, NULL)); + if(strstr(value, "expr(") ) { + my_strdup2(_ALLOC_ID_, &val, value); + value = eval_expr(translate3(val, 1, xctx->inst[inst].prop_ptr, template, NULL)); } if(!strcmp("@savecurrent", token)) { token_exists = 0; /* processed later */ @@ -2503,6 +2500,9 @@ int print_spice_element(FILE *fd, int inst) } dbg(1, "print_spice_element(): after translate() result=%s\n", result); } + if(strstr(result, "expr(") ) { + result = eval_expr(result); + } if(result) fprintf(fd, "%s", result); my_free(_ALLOC_ID_, &template); my_free(_ALLOC_ID_, &format); @@ -4490,11 +4490,9 @@ const char *translate(int inst, const char* s) i--; } if(strstr(value1, "expr(") == value1) { - char *ptr = strrchr(value1 + 5, ')'); dbg(1, "translate(): expr():%s\n", value1); - *ptr = '\0'; my_strdup2(_ALLOC_ID_, &value1, eval_expr( - translate3(value1 + 5, 1, xctx->inst[inst].prop_ptr, xctx->sym[xctx->inst[inst].ptr].templ, NULL))); + translate3(value1, 1, xctx->inst[inst].prop_ptr, xctx->sym[xctx->inst[inst].ptr].templ, NULL))); } tmp=strlen(value1); STR_ALLOC(&result, tmp + result_pos, &size); @@ -4521,12 +4519,10 @@ const char *translate(int inst, const char* s) * can be calculated */ my_strdup2(_ALLOC_ID_, &translated_tok, spice_get_node(tcl_hook2(result))); - if(strstr(translated_tok, "expr(") == translated_tok) { - char *ptr = strrchr(translated_tok + 5, ')'); + if(strstr(translated_tok, "expr(")) { dbg(1, "translate(): expr():%s\n", translated_tok); - *ptr = '\0'; my_strdup2(_ALLOC_ID_, &translated_tok, eval_expr( - translate3(translated_tok + 5, 1, xctx->inst[inst].prop_ptr, xctx->sym[xctx->inst[inst].ptr].templ, NULL))); + translate3(translated_tok, 1, xctx->inst[inst].prop_ptr, xctx->sym[xctx->inst[inst].ptr].templ, NULL))); } return translated_tok;