NAPA Compiler V4.50
Author: Yves Leduc, yves.leduc.be@gmail.com
Loading...
Searching...
No Matches
C:/Simulate/Napados/Source/tk.c
Go to the documentation of this file.
1/* ** TOKENS AND STRINGS ******************************************************************************************************** */
2
3#undef EXTERN
4#define EXTERN extern
5
6#include "./napa.h"
7#include "./proto.h"
8
9
10/* ****************************************************************************************************************************** */
11
12/* Works with UNIX file naming style. GNU compiler uses UNIX file naming, happily, with DOS also! */
13
14
15/* *** In this file: ************************************************************************************************************ */
16
17/* char *build_name(const char *sgn, char *tok, long lr_type); */
18/* char *compact_line(char *str1, char *str2) */
19/* char *expand_nodeset(char *str, long n, long w, const unsigned long *mlin, const unsigned long *mfil) */
20/* char *extract_line(char *str1, char *str2) */
21/* char *extract_prefix(char *nam) */
22/* char *format_suffixed_number(double value, long places, const char *unit) */
23/* char *get_function_identifier(char *str, char *fun_id, char *fun_parm) */
24/* char *get_output_and_scaling(char *str, char *sgn, char *out, char *scl) */
25/* char *get_sign_and_token(char *str, char *sgn, char *tok) */
26/* char *get_token(char *str, char *tok, long keep_quotes) */
27/* char *get_token_between_braces(char *str, char *brc, char *tok) */
28/* char *multiple(char c, long n) */
29/* char *replace_char(char *s, char b, char a) */
30/* char *unique_name(void) */
31/* char *upper_to_lower(char *s) */
32
33/* int cistrcmp(const char *a, const char *b) */
34/* int f1flush(FILE *fp) */
35/* int fnstrcmp(char const *a, char const *b) */
36/* int is_an_extended_identifier(const char *tok) */
37/* int is_an_identifier(const char *tok) */
38/* int is_an_integer_number(const char *tok) */
39/* int is_a_string(char *str) */
40
41/* void build_pathname(const char *brc, char *tok, const char *path, const unsigned long *mlin, const unsigned long *mfil) */
42/* void clean_line(char *str) */
43/* void clean_parentheses(char *tok) */
44/* void drop_filename(char *pnam) */
45/* void drop_pathname(char *pnam) */
46/* void expand_indirections(char *str) */
47/* void expand_iterative_identifiers(char *str, unsigned long *mlin, const unsigned long *mfil) */
48/* void extract_directory(char *pn, char *fn, long depth) */
49/* void process_cell_line(char *buf, long d, const unsigned long *mlin, const unsigned long *mfil) */
50/* void replace_dollar(char *tok) */
51/* void replace_parentheses(char *tok) */
52/* void resolve_pathnames(char *lin, long d) */
53/* void restore_line(char *lin) */
54/* void simplify_pathname(char *pnam) */
55/* void strip_extension(char *fnam) */
56/* void strip_quotes(char *str) */
57
58
59/* ****************************************************************************************************************************** */
60
61/* This function is used to build the name of each C variable representing the nodes and variables of the NAPA netlist with a */
62/* proper prefix. As this function is used to build the C file, this is the right time to record the usage of the NAPA nodes and */
63/* variables. A left value representing a declaration or a definition, the node or the variable is not considered as used. A */
64/* right value represents an effective usage of the node or the variable, therefore it is tagged as used. */
65/* At the end of the NAPA compilation, the node and variable usage is verified and proper warning issued. */
66
67/* Node injection is processed here if the node is a right value. */
68
69char *build_name(const char *sgn, char *tok, long lr_type) { /* 'tok' is modified in the process! */
70 char sign[2] = {'\0'}; /* lr-type: left ot right of '=' in assignation */
71 char prefix[STRLENGTH] = {'\0'};
72 char buf1[2*STRLENGTH] = {'\0'};
73 char buf2[2*STRLENGTH] = {'\0'};
74 static char *ptr = (char*) NULL;
75 long n, tp;
76 if (0 == strcmp(sgn, "-")) {
77 (void) strcpy(sign, "-");
78 } else {
79 (void) strcpy(sign, "");
80 }
81 n = node_id(tok);
82 if (UNDEFINED != n) { /* node */
83 if (RIGHT_VALUE == lr_type) {
84 Node_List[n].used = true;
85 }
86 tp = get_type(tok);
87 if (DIGITAL_DATA_TYPE == tp) {
88 (void) strcpy(prefix, "inode_");
89 } else if (ANALOG_DATA_TYPE == tp) {
90 (void) strcpy(prefix, "dnode_");
91 } else {
92 (void) strcpy(prefix, "xnode_"); /* should not happen, will cause a C compiler error */
93 }
94 (void) snprintf(buf1, (size_t) (STRLENGTH-1L), "%s", Node_List[n].name1);
95 ptr = strchr(buf1, ':');
96 if ((char*) NULL != ptr) { /* correction to be compatible to ANSI-C ':'-> '__' */
97 *ptr = '\0'; /* cut string in 2 substrings */
98 (void) strcpy(buf2, buf1); /* copy part of identifier before ':' */
99 (void) strcat(buf2, "__"); /* introduce a double '_' to avoid name collision */
100 (void) strcat(buf2, ptr+1); /* copy part of identifier after ':' */
101 (void) strcpy(buf1, buf2); /* only one ':' is processed */
102 }
103 if ((Node_List[n].inject) && (RIGHT_VALUE == lr_type)) {
104 if ((2L*LENGTH(buf1) + 20L) >= STRLENGTH) {
105 print_error_location("node", Node_List[n].mline, Node_List[n].mfile);
106 (void) fprintf(STDERR, " string overflow, node name <%s%s> is too long, use shorter identifiers\n", prefix, buf1);
107 print_limits();
109 }
110 if (ANALOG_DATA_TYPE != Node_List[n].type) {
111 print_error_location("node", Node_List[n].mline, Node_List[n].mfile);
112 (void) fprintf(STDERR, " digital node, only injection on analog nodes is allowed\n");
114 }
115 (void) snprintf(tok, (size_t) (LINLENGTH-1L), "%s(%s%s + inject_%s)", sign, prefix, buf1, buf1);
116 } else {
117 if (STRLENGTH <= (LENGTH(buf1) + 8L)) {
118 print_error_location("node", Node_List[n].mline, Node_List[n].mfile);
119 (void) fprintf(STDERR, " string overflow, node name <%s%s> is too long, use shorter identifiers\n", prefix, buf1);
120 print_limits();
122 }
123 (void) snprintf(tok, (size_t) (LINLENGTH-1L), "%s%s%s", sign, prefix, buf1);
124 }
125 return tok;
126 }
127 n = var_id(tok); /* variable */
128 if (UNDEFINED != n) {
129 if (RIGHT_VALUE == lr_type) {
130 Var_List[n].used = true;
131 }
132 tp = get_type(tok);
133 if (0 != strncmp(tok, "const__", (size_t) 7)) { /* prefix for variables, not created constants */
134 if (DIGITAL_DATA_TYPE == tp) {
135 (void) strcpy(prefix, "ivar_");
136 } else if (ANALOG_DATA_TYPE == tp) {
137 (void) strcpy(prefix, "dvar_");
138 } else if (STRING_DATA_TYPE == tp) {
139 (void) strcpy(prefix, "svar_");
140 } else {
141 (void) strcpy(prefix, "xvar_"); /* should not happen, will cause a C compiler error */
142 }
143 } else { /* specific prefix for created constants */
144 if (DIGITAL_DATA_TYPE == tp) {
145 (void) strcpy(prefix, "i") ;
146 } else if (ANALOG_DATA_TYPE == tp) {
147 (void) strcpy(prefix, "d");
148 } else if (STRING_DATA_TYPE == tp) {
149 (void) strcpy(prefix, "s");
150 } else {
151 (void) strcpy(prefix, "x"); /* should not happen, will cause a C compiler error */
152 }
153 }
154 if (STRLENGTH <= (LENGTH(Var_List[n].name1) + 7L)) {
155 print_error_location("var", Var_List[n].mline, Var_List[n].mfile);
156 (void) fprintf(STDERR, " string overflow, var name <%s%s> is too long, use shorter identifiers\n", prefix, Var_List[n].name1);
157 print_limits();
159 }
160 (void) snprintf(tok, (size_t) (LINLENGTH-1L), "%s%s%s", sign, prefix, Var_List[n].name1);
161 return tok;
162 }
163 n = array_id(tok); /* array */
164 if (UNDEFINED != n) {
165 if (RIGHT_VALUE == lr_type) {
166 Array_List[n].used = true;
167 }
168 tp = get_type(tok);
169 if ((DIGITAL_DATA_TYPE == tp) || (HEX_DATA_TYPE == tp)) {
170 (void) strcpy(prefix, "i_array_");
171 } else if (ANALOG_DATA_TYPE == tp) {
172 (void) strcpy(prefix, "d_array_");
173 } else {
174 (void) strcpy(prefix, "x_array_"); /* should not happen, will cause a C compiler error */
175 }
176 if (STRLENGTH <= (LENGTH(Array_List[n].name) + 9L)) {
177 print_error_location("array", Array_List[n].mline, Array_List[n].mfile);
178 (void) fprintf(STDERR, " string overflow, array name <%s%s> is too long, use shorter identifiers\n", prefix, Array_List[n].name);
179 print_limits();
181 }
182 (void) snprintf(tok, (size_t) (LINLENGTH-1L), "%s%s%s", sign, prefix, Array_List[n].name);
183 return tok;
184 }
185 n = record_id(tok); /* array of pointers */
186 if (UNDEFINED != n) {
187 if (ISNOTEMPTY(sign)) {
188 (void) fprintf(STDERR, "\nNAPA Error:\n");
189 (void) fprintf(STDERR, " sign is not expected in front of a pointer array\n");
190 exit(EXIT_FAILURE);
191 }
192 (void) strcpy(prefix, "record_");
193 if (STRLENGTH <= (LENGTH(Record_List[n].name) + 9L)) {
194 print_error_location("record", Record_List[n].mline, Record_List[n].mfile);
195 (void) fprintf(STDERR, " string overflow, record name <%s%s> is too long, use shorter identifiers\n", prefix, Record_List[n].name);
196 print_limits();
198 }
199 if (RIGHT_VALUE == lr_type) {
200 Record_List[n].used = true;
201 (void) snprintf(tok, (size_t) (LINLENGTH-1L), "&%s%s", prefix, Record_List[n].name);
202 } else {
203 (void) snprintf(tok, (size_t) (LINLENGTH-1L), "%s%s", prefix, Record_List[n].name);
204 }
205 return tok;
206 }
207 (void) strcpy(buf1, tok); /* other: no process */
208 if (STRLENGTH <= (LENGTH(buf1) + 1L)) {
209 print_error_location("identifier", NULL, NULL);
210 (void) fprintf(STDERR, " string overflow, identifier name <%s> is too long, use shorter identifiers\n", buf1);
211 print_limits();
213 }
214 (void) snprintf(tok, (size_t) (LINLENGTH-1L), "%s%s", sign, buf1);
215 if (0 == strcmp(tok, "stdin" )) {
216 (void) strcpy(tok, "\"stdin\"");
217 }
218 if (0 == strcmp(tok, "stdout")) {
219 (void) strcpy(tok, "\"stdout\"");
220 }
221 if (0 == strcmp(tok, "stderr")) {
222 (void) strcpy(tok, "\"stderr\"");
223 }
224 return tok;
225}
226
227
228/* This function receives a string already splitted in 3 elements: braces, string, pathname */
229
230void build_pathname(const char *brc, char *tok, const char *path, const unsigned long *mlin, const unsigned long *mfil) {
231 char buf[LINLENGTH] = {'\0'};
232 char *s = (char*) NULL;
233 char *t = (char*) NULL;
234 if (0 == strcmp(brc, "<>")) { /* pathname of a file of a generic library */
235 (void) snprintf(buf, (size_t) (LINLENGTH-1L), "%s/%s", path, tok); /* complete path e.g."/NAPA/hdr" */
236 s = buf;
237 t = tok;
238 while ('\0' != *s) {
239 if (('.' != *s) && ('.' == *(s+1)) && ('/' == *(s+2))) { /* remove extra './' */
240 *t = *s;
241 s++;
242 t++;
243 s += 2;
244 }
245 *t = *s;
246 s++;
247 t++;
248 }
249 *t = '\0';
250 } else if (0 != strcmp(brc, "\"\"")) { /* a user's file */
251 print_error_location("pathname", mlin, mfil);
252 if (2L == LENGTH(brc)) {
253 (void) fprintf(STDERR, " %c%s%c is not a correct pathname\n", brc[0], tok, brc[1]);
254 } else {
255 (void) fprintf(STDERR, " the pathname <%s> is not correct\n", tok);
256 }
258 }
259 return;
260}
261
262
263/* A critical function which must handling pathnames but also strings in print format */
264
265void resolve_pathnames(char *lin, long depth) { /* following the NAPA file system conventions */
266 char *sl = (char*) NULL;
267 char *sb = (char*) NULL;
268 char *se = (char*) NULL;
269 char *sw = (char*) NULL;
270 char tk[LINLENGTH] = {'\0'};
271 char bf[LINLENGTH] = {'\0'};
272 char pn[LINLENGTH] = {'\0'};
273 char fn[LINLENGTH] = {'\0'};
274 long i, j, k;
275 sl = lin;
276 while ('\0' != *sl) {
277 (void) strcpy(tk, "");
278 while (('"' != *sl) && ('\0' != *sl)) { /* skip everything outside a string */
279 sl++;
280 }
281 if ('\0' == *sl) { /* end of line, no more process */
282 break;
283 }
284 sl++; /* symbol after double quote */
285 sb = sl; /* mark begin of the string: sb */
286 se = sl;
287 while (('"' != *sl) && ('\0' != *sl)) {
288 sl++;
289 }
290 if ('\0' == *sl) { /* end of line, no more process */
291 break;
292 }
293 if ('"' == *sl) {
294 se = sl - 1; /* mark end of the string: se */
295 sl++; /* symbol after double quote */
296 }
297 /* 'sb' points to first symbol of string, 'se' points to last symbol of string transfer string constant in array 'tk' */
298 i = 0L;
299 for (sw = sb; sw <= se; sw++) {
300 tk[i] = *sw;
301 i++; /* count the number of symbols */
302 }
303 i--;
304 tk[i] = '\0'; /* terminate string */
305 if (ISEMPTY(tk)) {
306 continue; /* no process, continue scanning */
307 }
308 (void) strcpy(pn, Cur_Lib_Name[depth]);
309 extract_directory(pn, tk, depth); /* follow NAPA file system */
310 (void) snprintf(fn, (size_t) (LINLENGTH-1L), "%s%s", pn, tk); /* 'fn' contains resolved file path */
311 /* build a new line containing the resolved name in array 'bf' */
312 i = 0L;
313 j = 0L;
314 for (sw = lin; sw < sb; sw++) { /* copy all before */
315 bf[i] = *sw;
316 i++;
317 }
318 for (sw = fn; sw < (&(fn[LENGTH(fn)])); sw++) { /* copy resolved pathname */
319 bf[i] = fn[j];
320 i++;
321 j++;
322 }
323 k = i + 1L; /* record where to continue */
324 for (sw = se; sw < (&(lin[LENGTH(lin)])); sw++) { /* append end of line */
325 bf[i] = *sw;
326 i++;
327 }
328 bf[i] = '\0';
329 (void) strcpy(lin, bf); /* copy to 'lin' */
330 sl = lin + k; /* points to next symbol */
331 }
332 return;
333}
334
335
336/* This function processes strings, these strings are tested to detect pathnames. */
337/* If a pathname is detected, the pathname is completed following the NAPA file system convention. */
338
339void extract_directory(char *pn, char *fn, long depth) { /* build directory pathname from dir and file */
340 long len; /* move pathname directory of 'fn' to 'pn' */
341 char *s = (char*) NULL;
342 char *t = (char*) NULL;
343 char buf1[LINLENGTH] = {'\0'};
344 char buf2[LINLENGTH] = {'\0'};
345 /* this is not a pathname for sure ? */
346 if ((char*) NULL == strstr(fn, "/")) {
347 (void) strcpy(pn, "");
348 return;
349 }
350 /* it is still possible that it is not a pathname */
351 (void) strcpy(buf1, fn);
352 (void) strcpy(buf2, "");
353 s = buf1 + ((int) strlen(buf1)) - 1; /* go to end of file */
354 while (('/' != *s) && (s >= buf1)) { /* go back to detect last slash */
355 s--;
356 }
357 s++;
358 *s = '\0'; /* place an end of string: dir pathname */
359 /* buf1[] contains now the part of directory pathname which was in the file name this directory follows the NAPA file system */
360 /* naming ? absolute pathname: "/ etc " */
361 if ('/' == buf1[0]) {
362 s = buf1; /* pathname without any modifications */
363 (void) strcpy(pn, s); /* pn: pathname without file name */
364 drop_pathname(fn); /* fn: file name without pathname */
365 /* ? path refers to dir containing main file: "~/ etc " */
366 } else if (('~' == buf1[0]) && ('/' == buf1[1])) {
367 t = buf1 + 2;
368 (void) snprintf(buf2, (size_t) (LINLENGTH-1L),"%s%s", Cur_Lib_Name[depth], t);
369 len = LENGTH(buf2);
370 if (LINLENGTH <= len) {
371 (void) fprintf(STDERR, "\nNAPA Error:\n");
372 (void) fprintf(STDERR, " string buffer overflow while tracking pathname\n");
373 (void) fprintf(STDERR, " current limit is %ld characters (LINLENGTH)\n", LINLENGTH);
374 exit(EXIT_FAILURE);
375 }
376 s = buf2;
377 (void) strcpy(pn, s); /* pn: pathname without file name */
378 drop_pathname(fn); /* fn: file name without pathname */
379 /* ? path refers to dir containing the cell file being processed "./ etc " */
380 } else if (('.' == buf1[0]) && ('/' == buf1[1])) {
381 t = buf1 + 2;
382 (void) snprintf(buf2, (size_t) (LINLENGTH-1L), "%s%s", pn, t); /* use pathname of function input */
383 len = LENGTH(buf2);
384 if (LINLENGTH <= len) {
385 (void) fprintf(STDERR, "\nNAPA Error:\n");
386 (void) fprintf(STDERR, " string buffer overflow while tracking pathname\n");
387 (void) fprintf(STDERR, " current limit is %ld characters (LINLENGTH)\n", LINLENGTH);
388 exit(EXIT_FAILURE);
389 }
390 s = buf2;
391 (void) strcpy(pn, s); /* pn: pathname without file name */
392 drop_pathname(fn); /* fn: file name without pathname */
393 /* ? refers to working directory " etc ", BUT also compatible with no pathname string */
394 } else {
395 s = buf1; /* pathname without any modifications */
396 (void) strcpy(pn, s); /* pn: pathname without file name */
397 drop_pathname(fn); /* fn: file name without pathname */
398 }
399 return;
400}
401
402
403void clean_parentheses(char *tok) { /* remove useless external parenthesis */
404 char buf[LINLENGTH] = {'\0'};
405 long n;
406 char *s = (char*) NULL;
407 s = tok;
408 if ('(' != *s) {
409 return; /* no simplification */
410 }
411 s += ((int) strlen(tok)) - 1;
412 if (')' != *s) {
413 return; /* no simplification */
414 }
415 s = tok;
416 n = 0L;
417 while ('\0' != *s) {
418 if ('(' == *s) {
419 n++;
420 } else if (')' == *s) {
421 n--;
422 }
423 s++;
424 if ((0L == n) && ('\0' != *s)) {
425 return; /* no simplification */
426 }
427 }
428 s = tok + 1; /* suppress first parenthesis */
429 (void) strcpy(buf, s);
430 s = buf + ((int) strlen(buf)) - 1;
431 *s = '\0'; /* suppress last parenthesis */
432 s = buf;
433 (void) strcpy(tok, s);
434 clean_parentheses(tok); /* recursive call to clean further */
435 return;
436}
437
438
439/* add prefix from cell hierarchy to local var, nodeset requires a specific processing */
440
441void process_cell_line(char *buf, long d, const unsigned long *mlin, const unsigned long *mfil) {
442 char *si = (char*) NULL;
443 char *so = (char*) NULL;
444 char *sw = (char*) NULL;
445 char *sb = (char*) NULL;
446 char *str1 = (char*) NULL;
447 char *str2 = (char*) NULL;
448 char li[LINLENGTH] = {'\0'};
449 char wi[LINLENGTH] = {'\0'};
450 char tok1[STRLENGTH] = {'\0'};
451 char tok2[LINLENGTH] = {'\0'};
452 char tok3[STRLENGTH] = {'\0'};
453 char tok4[STRLENGTH] = {'\0'};
454 char tok5[STRLENGTH] = {'\0'};
455 long c, m;
456 long b1, e1, b2, e2;
457 long i, j;
458 int node_flag;
459 int interface_flag;
460 int nodeset_flag;
461 node_flag = false;
462 interface_flag = false;
463 nodeset_flag = false;
464 if ((0L >= d) || ISEMPTY(buf)) { /* nothing to expand at main level or buffer empty */
465 return;
466 }
467 m = LINLENGTH / 8L; /* reasonable maximum to avoid overflow later */
468 if (LENGTH(buf) >= m) {
469 print_error_location( "check", mlin, mfil);
470 (void) fprintf(STDERR, " cell line too long to be expanded, refrain to use long identifiers, esp. long instantiation names!\n");
472 }
473 if (((char*) NULL == strstr(buf, " node")) && ((char*) NULL == strstr(buf, "node["))) {
474 node_flag = false;
475 } else {
476 node_flag = true;
477 }
478 (void) strcpy(li, buf);
479 c = 0L; /* expand local variables */
480 so = buf;
481 si = li; /* scan and process */
482 while (isspace((int) *si) && ('\0' != *si)) {
483 si++; /* remove spaces on the left */
484 }
485
486 while ('\0' != *si) { /* process all char of the line */
487
488 if ('$' == *si) {
489
490 /* local identifier, process */
491 sw = tok1; /* get token starting with $ */
492 while (isalnum((int) *si) || ('$' == *si) || ('_' == *si) || ('.' == *si) || ('@' == *si)) {
493 *sw = *si;
494 sw++;
495 si++;
496 }
497 *sw = '\0'; /* terminate token 'tok1' */
498
499 if (node_flag) { /* it is a node. Is it a nodeset? */
500 str1 = tok1;
501 for (;;) {
502 if (!isspace((int) *str1) && ('[' != *str1)) {
503 nodeset_flag = false;
504 break;
505 }
506 if ('[' == *str1) {
507 nodeset_flag = true;
508 (void) strcpy(tok2, str1);
509 break;
510 }
511 if ('\0' == *str1) {
512 nodeset_flag = false;
513 break;
514 }
515 str1++;
516 }
517 } else {
518 nodeset_flag = false;
519 }
520
521 if (nodeset_flag) { /* nodeset analysis */
522 interface_flag = false;
523 (void) strcpy(tok3, tok1);
524 str1 = tok3;
525 for (;;) {
526 if ('[' == *str1) {
527 break;
528 }
529 if ('\0' == *str1) {
530 break;
531 }
532 str1++;
533 }
534 *str1 = '\0';
535 if (2 != sscanf(tok2, "[%li..%li]", &b1, &e1)) { /* iterator */
536 print_error_location("cell", mlin, mfil);
537 (void) fprintf(STDERR, " nodeset iterator is not well-formed <%s> in <%s>\n", tok2, tok1);
539 }
540 if (b1 < e1) { /* begin, end redefinition */
541 b2 = b1;
542 e2 = e1;
543 } else {
544 b2 = e1;
545 e2 = b1;
546 }
547 i = b2;
548 (void) snprintf(tok2, (size_t) (LINLENGTH-1L), "%s%ld", tok3, i); /* single node from nodeset */
549 for (j = 0L; j < Cell_Num_Parms[d]; j++) { /* identify correspondance */
550 if (0 == strcmp(Cell_Plist[d][j], tok2)) { /* member of interface */
551 interface_flag = true;
552 break;
553 }
554 }
555 if (interface_flag) { /* other nodes are interface? */
556 for (i = b2+1L; i <= e2; i++) {
557 (void) snprintf(tok2, (size_t) (LINLENGTH-1L), "%s%ld", tok3, i); /* single node from nodeset */
558 interface_flag = false;
559 for (j = 0L; j < Cell_Num_Parms[d]; j++) { /* identify correspondance */
560 if (0 == strcmp(Cell_Plist[d][j], tok2)) { /* member of interface */
561 interface_flag = true;
562 break;
563 }
564 }
565 if (!interface_flag) {
566 print_error_location("cell", mlin, mfil);
567 (void) fprintf(STDERR, " first node of the nodeset is part of interface,\n");
568 (void) fprintf(STDERR, " but the nodeset is not composed of interface nodes\n");
570 }
571 }
572 } else { /* other nodes are not interface? */
573 for (i = b2+1L; i <= e2; i++) {
574 (void) snprintf(tok2, (size_t) (LINLENGTH-1L), "%s%ld", tok3, i); /* single node from nodeset */
575 for (j = 0L; j < Cell_Num_Parms[d]; j++) { /* identify correspondance */
576 if (0 == strcmp(Cell_Plist[d][j], tok2)) { /* member of interface */
577 print_error_location("cell", mlin, mfil);
578 (void) fprintf(STDERR, " first node of the nodeset is an internal node,\n");
579 (void) fprintf(STDERR, " but the nodeset is not composed of internal nodes\n");
581 }
582 }
583 }
584 }
585 (void) snprintf(tok1, (size_t) (STRLENGTH-1L), "%s[%ld..%ld]", tok3, b1, e1);
586 if (!interface_flag) { /* local identifier */
587 sw = Cell_Name_Prefix[d];
588 while ('\0' != *sw) {
589 *so = *sw;
590 so++;
591 sw++;
592 c++;
593 }
594 *so++ = '_';
595 *so++ = '_';
596 c += 2L;
597 sw = tok1;
598 sw++; /* skip '$' */
599 while ('\0' != *sw) {
600 *so = *sw;
601 so++;
602 sw++;
603 c++;
604 }
605 } else {
606 sw = tok1;
607 sw++; /* skip '$' */
608 while ('\0' != *sw) {
609 *so = *sw;
610 so++;
611 sw++;
612 c++;
613 }
614 }
615
616 } else { /* it is not a nodeset */
617
618 interface_flag = false;
619
620 /* simple token */
621 for (j = 0L; j < Cell_Num_Parms[d]; j++) { /* identify correspondance */
622 (void) strcpy(tok4, tok1); /* must also process "arrayid.number" identifier */
623 str2 = strchr(tok4, '.');
624 if ((char*) NULL != str2) {
625 (void) strcpy(tok5, str2); /* contains the rest of identifier including '.' */
626 *str2 = '\0'; /* 'tok4' contains the id of the array */
627 } else {
628 (void) strcpy(tok5, "");
629 }
630 if (0 == strcmp(Cell_Plist[d][j], tok4)) { /* member of cell interface */
631 interface_flag = true;
632 (void) strcpy(wi, Inst_Plist[d][j]);
633 (void) strcat(wi, tok5); /* copy right part of identifier "arrayid.number" */
634 sw = wi; /* copy to avoid side effect */
635 if ('-' != *sw) { /* unsigned replacement */
636 while ('\0' != *sw) {
637 *so = *sw;
638 so++;
639 sw++;
640 c++;
641 }
642 } else { /* signed replacement!!! */
643 if (so > li) {
644 sb = so - 1;
645 } else {
646 sb = so;
647 }
648 while ((sb >= li) && (' ' == *sb)) { /* find previous non blank */
649 sb--;
650 }
651 if ('-' == *sb) { /* a minus! */
652 *sb = '+'; /* change sign */
653 *sw = ' '; /* remove minus from copy */
654 }
655 while ('\0' != *sw) {
656 *so = *sw;
657 so++;
658 sw++;
659 c++;
660 }
661 }
662 break;
663 }
664 }
665
666 if (!interface_flag) { /* local identifier */
667 sw = Cell_Name_Prefix[d];
668 while ('\0' != *sw) {
669 *so = *sw;
670 so++;
671 sw++;
672 c++;
673 }
674 *so++ = '_';
675 *so++ = '_';
676 c += 2L;
677 sw = tok1;
678 sw++; /* skip '$' */
679 while ('\0' != *sw) {
680 *so = *sw;
681 so++;
682 sw++;
683 c++;
684 }
685 }
686 }
687
688 } else { /* normal text without prefix $ */
689
690 while (('$' != *si) && ('\0' != *si) && !isspace((int) *si)) {
691 *so = *si;
692 so++;
693 si++;
694 c++;
695 }
696 while (isspace((int) *si) && ('\0' != *si)) { /* space */
697 *so = *si;
698 so++;
699 si++;
700 c++;
701 }
702 }
703
704 if (c >= m) { /* verify length after each word */
705 print_error_location( "check", mlin, mfil);
706 (void) fprintf(STDERR, " line too long, overflow occured during expansion of cell line\n");
707 print_limits();
709 }
710 } /* end of process of all line */
711
712 *so = '\0'; /* terminate string */
713 return;
714}
715
716
717void expand_indirections(char *str) {
718 double d;
719 char *s = (char*) NULL;
720 char *b = (char*) NULL;
721 char *t = (char*) NULL;
722 char *v = (char*) NULL;
723 char buf[LINLENGTH] = {'\0'};
724 char tok[STRLENGTH] = {'\0'};
725 char val[STRLENGTH] = {'\0'};
726 long m;
727 (void) strcpy(buf, str);
728 b = buf;
729 s = str;
730 while ('\0' != *b) {
731 if ('#' != *b) {
732 *s = *b;
733 b++;
734 s++;
735 } else {
736 b++;
737 t = tok;
738 while (isalnum((int) *b) || ('_' == *b) || (':' == *b) || ('@' == *b)) {
739 *t = *b;
740 b++;
741 t++;
742 }
743 *t = '\0';
744 m = var_id(tok);
745 if (UNDEFINED != m) {
746 Var_List[m].used = true;
747 if (ISNOTEMPTY(Var_List[m].value)) {
748 if (ANALOG_DATA_TYPE == constant_type(Var_List[m].value)) { /* format the analog number */
749 if (1 == sscanf(Var_List[m].value, "%lf", &d)) {
750 (void) snprintf(val, (size_t) (STRLENGTH-1L), "%s", format_suffixed_number(d, 3, ""));
751 } else {
752 (void) strcpy(val, Var_List[m].value);
753 }
754 } else {
755 (void) strcpy(val, Var_List[m].value);
756 }
757 } else {
758 (void) strcpy(val, Var_List[m].value);
759 }
760 } else if ((0 == strcmp(tok, "fs")) && (Periodic_Flag)) {
761 (void) snprintf(val, (size_t) (STRLENGTH-1L), "%s", format_suffixed_number(Sampling_List.frequency, 3, " Hz"));
762 } else if ((0 == strcmp(tok, "ts")) && (Periodic_Flag)) {
763 (void) snprintf(val, (size_t) (STRLENGTH-1L), "%s", format_suffixed_number(Sampling_List.period, 3, " s" ));
764 } else if (0 == strcmp(tok, "random_seed")) {
765 (void) snprintf(val, (size_t) (STRLENGTH-1L), "%ld", Seed_List.rndseed);
766 } else if (UNDEFINED != get_type(tok)) {
767 (void) strcpy(val, tok);
768 } else {
769 (void) strcpy(val, "???");
770 }
771 m = directive_id(tok);
772 if (UNDEFINED != m) {
773 if (ISNOTEMPTY(Directive_List[m].value)) {
774 (void) strcpy(val, Directive_List[m].value);
775 } else {
776 (void) strcpy(val, "?");
777 }
778 }
779 v = val;
780 while ('\0' != *v) {
781 if ('"' != *v) {
782 *s = *v;
783 s++;
784 }
785 v++;
786 }
787 *s = ' ';
788 *v = '\0';
789 }
790 }
791 *s = '\0';
792 return;
793}
794
795
796void expand_iterative_identifiers(char *str, unsigned long *mlin, const unsigned long *mfil) {
797 char buf[LINLENGTH] = {'\0'};
798 char tok1[STRLENGTH] = {'\0'};
799 char tok2[STRLENGTH] = {'\0'};
800 char tok3[STRLENGTH] = {'\0'};
801 char tok4[LINLENGTH] = {'\0'};
802 char *s = (char*) NULL;
803 char *t = (char*) NULL;
804 char *u = (char*) NULL;
805 char *n = (char*) NULL;
806 char *b = (char*) NULL;
807 char *e = (char*) NULL;
808 char *f = (char*) NULL;
809 long i, begin, end;
810
811 (void) strcpy(buf, str);
812
813 s = str;
814 t = buf;
815 u = buf + (7*LINLENGTH)/8; /* reserve some margin */
816
817 /* principle: scan 'buf' (pointer t), process and write back in 'str' (pointer s) */
818
819 while (('\0' != *t) && (t < u)) {
820
821 if (('.' == *t) && ('.' == *(t+1))) { /* PERHAPS AN ITERATIVE IDENTIFIER? */
822 n = tok1;
823 b = tok2;
824 e = tok3;
825
826 while ((!isspace((int) *t)) && (t != buf)) { /* go backwards until beginning of token */
827 s--;
828 t--;
829 }
830 while (('.' != *t) && ('\0' != *t)) { /* stops at '.' */
831 *n = *t;
832 t++;
833 n++;
834 }
835 if ('.' != *(t+1)) { /* not a double point, an array of pointer element */
836 *n = *t;
837 t++;
838 n++;
839 }
840 while (('.' != *t) && ('\0' != *t)) { /* stops at '.' */
841 *n = *t;
842 t++;
843 n++;
844 }
845 t--;
846 while ((isdigit((int) *t)) && (t != buf)) {
847 t--;
848 n--;
849 }
850 *n = '\0';
851 if (ISEMPTY(tok1)) { /* not an iterative identifier, ignore! */
852 t += 2;
853 continue;
854 }
855 do { /* get id start */
856 t++;
857 *b = *t;
858 b++;
859 } while (('.' != *t) && ('\0' != *t));
860 b--;
861 *b = '\0';
862 if (1 > sscanf(tok2, "%li", &begin)) { /* tok2 contains the first number */
863 *mlin = *mlin + 1UL;
864 print_error_location("iterative identifier", mlin, mfil);
865 (void) fprintf(STDERR, " error during expansion of start index of identifier <%s>\n", tok1);
866 *s = '\0';
868 }
869 t++;
870 do { /* get id end */
871 t++;
872 *e = *t;
873 e++;
874 } while ((!isspace((int) *t)) && ('\0' != *t));
875 e--;
876 *e = '\0';
877 if (1 > sscanf(tok3, "%li", &end)) { /* tok3 contains the second number */
878 *mlin = *mlin + 1UL;
879 print_error_location("iterative identifier", mlin, mfil);
880 (void) fprintf(STDERR, " error during expansion of stop index of identifier <%s>\n", tok1);
881 *s = '\0';
883 }
884 while ((!isspace((int) *s)) && (s != str)) {
885 s--;
886 }
887 t--;
888 /* generate the identifiers: forward counting or backward counting */
889 if (begin <= end) { /* forward counting */
890 for (i = begin; i <= end; i++) {
891 (void) snprintf(tok4, (size_t) (LINLENGTH-1L), " %s%ld", tok1, i);
892 f = tok4;
893 while ('\0' != *f) {
894 *s = *f;
895 s++;
896 f++;
897 }
898 }
899 } else { /* backward counting */
900 for (i = begin; i >= end; i--) {
901 (void) snprintf(tok4, (size_t) (LINLENGTH-1L), " %s%ld", tok1, i);
902 f = tok4;
903 while ('\0' != *f) {
904 *s = *f;
905 s++;
906 f++;
907 }
908 }
909 }
910 *s = ' ';
911 s--;
912 continue;
913 }
914
915 if ('"' == *t) { /* copy string, no change */
916 do {
917 *s = *t;
918 s++;
919 t++;
920 } while (('"' != *t) && ('\0' != *t));
921 *s = *t;
922 t++;
923 s++;
924 continue;
925 }
926
927 if ('<' == *t) { /* copy string, NAPA library file, no change */
928 do {
929 *s = *t;
930 s++;
931 t++;
932 } while (('>' != *t) && ('\0' != *t));
933 *s = *t;
934 t++;
935 s++;
936 continue;
937 }
938
939 if ('[' == *t) { /* copy characters between brackets, no change */
940 do {
941 *s = *t;
942 s++;
943 t++;
944 } while ((']' != *t) && ('\0' != *t));
945 *s = *t;
946 t++;
947 s++;
948 continue;
949 }
950
951 /* normal identifier: copy char by char */
952 *s = *t;
953 s++;
954 t++;
955
956 }
957
958 if (t >= u) {
959 print_error_location("iterative identifier", mlin, mfil);
960 (void) fprintf(STDERR, " overflow during line expansion, please limit the iteration span\n");
962 }
963
964 *s = '\0';
965 return;
966}
967
968
969char *expand_nodeset(char *str, long n, long w, const unsigned long *mlin, const unsigned long *mfil) {
970 char tok1[LINLENGTH] = {'\0'};
971 char tok2[LINLENGTH] = {'\0'};
972 char iter[STRLENGTH] = {'\0'};
973 char ch[STRLENGTH] = {'\0'};
974 char *s1 = (char*) NULL;
975 char *s2 = (char*) NULL;
976 char *s3 = (char*) NULL;
977 long i1, i2, i, j;
978 int flag;
979 (void) strcpy(tok1, str);
980 s1 = tok1;
981 s2 = tok2;
982 while ('\0' != *s1) {
983 while (('[' != *s1) && ('\0' != *s1)) {
984 *s2 = *s1;
985 s1++;
986 s2++;
987 }
988 s1++;
989 (void) strcpy(iter, "");
990 s3 = iter;
991 while ((']' != *s1) && ('\0' != *s1)) {
992 if ('.' == *s1) {
993 *s3 = ' ';
994 } else {
995 *s3 = *s1;
996 }
997 s1++;
998 s3++;
999 }
1000 s1++;
1001 *s3 = '\0';
1002 if (ISEMPTY(iter)) {
1003 break;
1004 }
1005 flag = sscanf(iter, "%li %li", &i1, &i2); /* process iterator */
1006 if (2 != flag) {
1007 print_error_location("syntax", mlin, mfil);
1008 (void) fprintf(STDERR, " invalid iterator [%s] in nodeset\n", iter);
1010 }
1011 if (((i2-i1) != (w-1L)) && ((i1-i2) != (w-1L))) {
1012 print_error_location("syntax", mlin, mfil);
1013 (void) fprintf(STDERR, " iterator [%ld..%ld] does not match nodeset declaration [%ld]\n", i1, i2, w);
1015 }
1016 if (i2 > i1) {
1017 i = i1 + n;
1018 } else {
1019 i = i1 - n;
1020 }
1021 (void) snprintf(ch, (size_t) (STRLENGTH-1L), "%ld", i);
1022 for (j = 0L; 6L > j; j++) {
1023 if ('\0' == ch[j]) {
1024 break;
1025 }
1026 *s2 = ch[j];
1027 s2++;
1028 }
1029 }
1030 *s2 = '\0';
1031 (void) strcpy(str, tok2);
1032 return str;
1033}
1034
1035
1036char *get_function_identifier(char *str, char *fun_id, char *fun_parm) {
1037 long n;
1038 char tok1[STRLENGTH] = {'\0'};
1039 char tok2[STRLENGTH] = {'\0'};
1040 char sgn[2] = {'\0'};
1041 char brc[3] = {'\0'};
1042 static char *b = (char*) NULL;
1043 str = get_sign_and_token(str, sgn, tok1); /* get possible identifier */
1044 b = str;
1045 n = directive_id(tok1); /* ignore defined directive */
1046 if (UNDEFINED != n) {
1047 str = get_sign_and_token(str, sgn, tok1); /* get next possible identifier */
1048 }
1049 (void) get_token_between_braces(str, brc, tok2);
1050 if (ISNOTEMPTY(tok1) && (0 == strcmp(brc, "()")) && (is_an_identifier(tok1)) && (' ' != *(b-1))) { /* ignore option */
1051 (void) strcpy(fun_id, tok1);
1052 (void) strcpy(fun_parm, tok2);
1053 } else {
1054 (void) strcpy(fun_id, ""); /* no success */
1055 (void) strcpy(fun_parm, "");
1056 }
1057 return b;
1058}
1059
1060
1061char *get_output_and_scaling(char *str, char *sgn, char *out, char *scl) {
1062 char tok1[STRLENGTH] = {'\0'};
1063 char tok2[STRLENGTH] = {'\0'};
1064 char brc[3] = {'\0'};
1065 char *b = (char*) NULL;
1066 str = get_sign_and_token(str, sgn, tok1); /* get output with sign */
1067 do {
1068 b = strchr(tok1, '\'');
1069 if ((char*) NULL != b) {
1070 *b = '$'; /* replace character ' by $ */
1071 }
1072 } while ((char*) NULL != b);
1073 b = str;
1074 str = get_token_between_braces(str, brc, tok2); /* get scaling if it exists */
1075 if (ISNOTEMPTY(tok1) && (0 == strcmp(brc, "()")) && (is_an_identifier(tok1)) && (' ' != *(b-1))) { /* ignore scaling */
1076 (void) strcpy(out, tok1); /* scaling */
1077 (void) strcpy(scl, tok2);
1078 } else {
1079 (void) strcpy(out, tok1); /* no scaling */
1080 (void) strcpy(scl, "");
1081 }
1082 return str;
1083}
1084
1085
1086char *extract_prefix(char *nam) {
1087 char *s = (char*) NULL;
1088 char *t = (char*) NULL;
1089 long len;
1090 s = nam;
1091 t = nam;
1092 len = LENGTH(nam);
1093 if (3L >= len) {
1094 *s = '\0';
1095 return nam;
1096 }
1097 t += ((int) len) - 3;
1098 while (s != t) {
1099 if (('_' == *s) || ('_' == *(s+1))) {
1100 *(s+3) = '\0';
1101 return nam;
1102 }
1103 s++;
1104 }
1105 *(s-3) = '\0';
1106 return nam;
1107}
1108
1109
1110char *get_token_between_braces(char *str, char *brc, char *tok) { /* no braces: no token extracted */
1111 char wrd[STRLENGTH] = {'\0'};
1112 char *s = (char*) NULL;
1113 char *b = (char*) NULL;
1114 char *w = (char*) NULL;
1115 char c1, c2;
1116 long i, j, cnt;
1117 s = str;
1118 while (isspace((int) *s)) { /* skip whitespace */
1119 s++;
1120 }
1121 b = brc;
1122 w = wrd;
1123 c1 = *s;
1124 if (('(' != c1) && ('<' != c1) && ('[' != c1) && ('{' != c1) && ('"' != c1) && ('\'' != c1)) {
1125 (void) strcpy(brc, ""); /* no brace */
1126 (void) strcpy(tok, ""); /* no token between braces */
1127 return str; /* statu quo! pointer remains as it was positionned */
1128 }
1129 *b = c1; /* brace found, copy left brace */
1130 cnt = 1L;
1131 if ('(' == c1) {
1132 c2 = ')';
1133 } else if ('<' == c1) {
1134 c2 = '>';
1135 } else if ('[' == c1) {
1136 c2 = ']';
1137 } else if ('{' == c1) {
1138 c2 = '}';
1139 } else if ('"' == c1) {
1140 c2 = '"';
1141 } else if ('\'' == c1) {
1142 c2 = '\'';
1143 } else {
1144 c2 = ' ';
1145 }
1146 b++;
1147 s++;
1148 while (('\0' != *s) && (0 < cnt)) { /* scan text between braces */
1149 if (*s == c2) { /* for quotes, mandatory to check in this order ! */
1150 cnt--;
1151 } else if (*s == c1) {
1152 cnt++;
1153 }
1154 *w = *s;
1155 s++;
1156 w++;
1157 }
1158 s--;
1159 w--;
1160 *w = '\0';
1161 j = 0L;
1162 for (i = 0L; i < LENGTH(wrd); i++) { /* get text between braces, replace tabs */
1163 if ('\t' == wrd[i]) {
1164 wrd[i] = ' ';
1165 continue;
1166 }
1167 tok[j] = wrd[i];
1168 j++;
1169 }
1170 tok[j] = '\0';
1171 if (*s == c2) {
1172 *b = *s; /* copy right brace */
1173 } else {
1174 (void) strcpy(brc, ""); /* no brace */
1175 (void) strcpy(tok, ""); /* no token between braces */
1176 return str; /* statu quo! pointer remains as it was positionned */
1177 }
1178 b++;
1179 *b = '\0';
1180 s++;
1181 while (isspace((int) *s)) { /* skip whitespace */
1182 s++;
1183 }
1184 return s; /* return pointer positionned after double brace */
1185}
1186
1187
1188char *get_sign_and_token(char *str, char *sgn, char *tok) {
1189 char buf[STRLENGTH] = {'\0'};
1190 str = get_token(str, buf, true); /* strings must be preserved */
1191 if (0 == strcmp(buf, "+")) {
1192 (void) strcpy(sgn, "+");
1193 str = get_token(str, tok, false);
1194 } else if (0 == strcmp(buf, "-")) {
1195 (void) strcpy(sgn, "-");
1196 str = get_token(str, tok, false);
1197 } else {
1198 (void) strcpy(sgn, "");
1199 (void) strcpy(tok, buf);
1200 }
1201 return str;
1202}
1203
1204
1205/* This function is one of the most critical function as all the parsing relies on its characteristics. */
1206
1207/* two choices: keep_quotes : double quotes are part of the token */
1208/* !keep_quotes : double quotes are removed from the token */
1209
1210char *get_token(char *str, char *tok, long keep_quotes) {
1211 char *t = (char*) NULL;
1212 char a, b;
1213 t = tok;
1214 while (isspace((int) *str)) { /* skip whitespace and tab */
1215 str++;
1216 }
1217 if ('"' == *str) { /* if first char== '"', read til '"' or end of line */
1218 if (keep_quotes) { /* record or drop quotes */
1219 *(t++) = *(str++);
1220 } else {
1221 str++;
1222 }
1223 while (('"' != *str) && ('\0' != *str)) {
1224 *(t++) = *(str++);
1225 }
1226 if ('"' == *str) {
1227 if (keep_quotes) { /* record or drop quotes */
1228 *(t++) = *(str++);
1229 } else {
1230 str++;
1231 }
1232 }
1233 } else if (('>' == *str) && ('=' == *(str+1))) { /* 'greater than' >= */
1234 *(t++) = *(str++);
1235 *t = *str;
1236 str++;
1237 t++;
1238 } else if (('<' == *str) && ('=' == *(str+1))) { /* 'smaller than' <= */
1239 *(t++) = *(str++);
1240 *t = *str;
1241 str++;
1242 t++;
1243 } else if (('=' == *str) && ('=' == *(str+1))) { /* 'equal to' == */
1244 *(t++) = *(str++);
1245 *t = *str;
1246 str++;
1247 t++;
1248 } else if (('!' == *str) && ('=' == *(str+1))) { /* 'not equal to' != */
1249 *(t++) = *(str++);
1250 *t = *str;
1251 str++;
1252 t++;
1253 } else if (('>' == *str) && ('>' == *(str+1))) { /* 'left shift << */
1254 *(t++) = *(str++);
1255 *t = *str;
1256 str++;
1257 t++;
1258 } else if (('<' == *str) && ('<' == *(str+1))) { /* 'right shift' >> */
1259 *(t++) = *(str++);
1260 *t = *str;
1261 str++;
1262 t++;
1263 } else if (('&' == *str) && ('&' == *(str+1))) { /* 'logical and' && */
1264 *(t++) = *(str++);
1265 *t = *str;
1266 str++;
1267 t++;
1268 } else if (('|' == *str) && ('|' == *(str+1))) { /* 'logical or' || */
1269 *(t++) = *(str++);
1270 *t = *str;
1271 str++;
1272 t++;
1273 } else if (('?' == *str) || (':' == *str) || ('%' == *str)) {
1274 *(t++) = ' ';
1275 *(t++) = *(str++);
1276 *(t++) = ' ';
1277 } else if (('0' == *str) && (('x' == *(str+1)) || ('X' == *(str+1)))) { /* hexa number */
1278 *(t++) = *(str++);
1279 if ('X' == *str) {
1280 *t = 'x';
1281 } else {
1282 *t = *str;
1283 }
1284 str++;
1285 t++;
1286 while (isdigit((int) *str)
1287 || ('a' == *str) || ('b' == *str) || ('c' == *str) || ('d' == *str) || ('e' == *str) || ('f' == *str)
1288 || ('A' == *str) || ('B' == *str) || ('C' == *str) || ('D' == *str) || ('E' == *str) || ('F' == *str)) {
1289 *t = (char) toupper((int) *str);
1290 str++;
1291 t++;
1292 }
1293 } else if (isdigit((int) *str)) { /* if it starts with a digit, get the entire number */
1294 while (isdigit((int) *str) || ('.' == *str) || ('e' == *str) || ('E' == *str) || ('L' == *str) || ('F' == *str)) {
1295 if (('e' == *str) || ('E' == *str)) {
1296 a = *(str + 1);
1297 b = *(str + 2);
1298 if (isdigit((int) a) || ((('+' == a) || ('-' == a)) && isdigit((int) b))) {
1299 *(t++) = *(str++);
1300 *(t++) = *(str++);
1301 } else {
1302 break;
1303 }
1304 } else {
1305 *(t++) = *(str++);
1306 }
1307 }
1308 } else { /* otherwise read all continuous alphanumeric */
1309 while (isalnum((int) *str) || ('_' == *str) || (':' == *str) || ('$' == *str) || ('°' == *str)
1310 || ('\'' == *str) || ('#' == *str) || ('.' == *str) || ('@' == *str) || ('&' == *str)) {
1311 *(t++) = *(str++);
1312 }
1313 }
1314 if ((t == tok) && ('\0' != *str)) { /* if it was something else (symbol), get it alone */
1315 *(t++) = *(str++);
1316 }
1317 *t = '\0';
1318 while (isspace((int) *str)) { /* get rid of following whitespace and tab */
1319 str++;
1320 }
1321 return str;
1322}
1323
1324
1325/* syntax name as a correct NAPA identifier */
1326
1327int is_an_identifier(const char *tok) {
1328 char tok1[STRLENGTH] = {'\0'};
1329 char *s = (char*) NULL;
1330 (void) strcpy(tok1, tok);
1331 s = tok1;
1332 if ('$' == tok1[LENGTH(tok1) - 1L]) { /* temporary spelling of qualifier '..$' */
1333 tok1[LENGTH(tok1) - 1L] = '\0'; /* remove the '$' before checking */
1334 }
1335 if (isdigit((int) *s) || (('_' == *s) && (0 != strncmp(tok1, "_void", (size_t) 5)))) {
1336 return false;
1337 }
1338 while ('\0' != *s) {
1339 if ((!isalnum((int) *s)) && ('_' != *s) && (':' != *s) && ('@' != *s) && ('\'' != *s)) {
1340 return false;
1341 }
1342 s++;
1343 }
1344 return true;
1345}
1346
1347
1348int is_an_extended_identifier(const char *tok) { /* may include also a '.' */
1349 char tok1[STRLENGTH] = {'\0'};
1350 char *s = (char*) NULL;
1351 (void) strcpy(tok1, tok);
1352 s = tok1;
1353 if ('$' == tok1[LENGTH(tok1) - 1L]) { /* temporary spelling of qualifier '..$' */
1354 tok1[LENGTH(tok1) - 1L] = '\0'; /* remove the '$' before checking */
1355 }
1356 if (isdigit((int) *s) || (('_' == *s) && (0 != strncmp(tok1, "_void", (size_t) 5)))) {
1357 return false;
1358 }
1359 while ('\0' != *s) {
1360 if ((!isalnum((int) *s)) && ('_' != *s) && (':' != *s) && ('.' != *s) && ('@' != *s) && ('\'' != *s)) {
1361 return false;
1362 }
1363 s++;
1364 }
1365 return true;
1366}
1367
1368
1369int is_a_string(char *str) {
1370 char tok[STRLENGTH] = {'\0'};
1371 char *s = (char*) NULL;
1372 s = tok;
1373 (void) compact_line(str, s);
1374 return (('"' == s[0]) && ('"' == s[LENGTH(s)-1L]) ? true : false);
1375}
1376
1377
1378int is_an_integer_number(const char *str) {
1379 char *s = (char*) NULL;
1380 double d;
1381 if (((char*) NULL == str) || ('\0' == *str) || isspace((int) *str)) {
1382 return false;
1383 }
1384 d = strtod(str, &s);
1385 if ('\0' != *s) {
1386 return false;
1387 }
1388 if ((double) ((long long) d) != d) {
1389 return false;
1390 }
1391 return true;
1392}
1393
1394
1395/* Remove right hand comment, clear commented line, replace tabs by one blank */
1396
1397void clean_line(char *str) {
1398 char *s = (char*) NULL;
1399 char *t = (char*) NULL;
1400 int flag;
1401 flag = false;
1402 t = str; /* remove NAPA comments <//...> of end of line */
1403 while (!((('/' == *t) && ('/' == *(t+1)) && (!flag)) || ('\0' == *t))) {
1404 if ('"' == *t) {
1405 flag = !flag; /* string can include double slash */
1406 }
1407 t++;
1408 }
1409 *t = '\0';
1410
1411 t = str;
1412 while ('\0' != *t) { /* replace any space (like tabs) by one blank */
1413 if (isspace((int) *t)) {
1414 *t = ' ';
1415 }
1416 t++;
1417 }
1418
1419 t = str;
1420 s = str;
1421 while ((isspace((int) *t)) && (isspace((int) *(t+1)))) { /* shrink double blanks */
1422 t++;
1423 }
1424
1425 if ('#' == *t) {
1426 *str = '#';
1427 *(str+1) = '\0'; /* comment is cleared, process is completed */
1428 return;
1429 }
1430
1431 while (('\0' != *t) && ('\n' != *t)) {
1432 *s = *t;
1433 s++;
1434 t++;
1435 }
1436 *s = '\0';
1437 *t = '\0';
1438
1439 while (('\0' == *s) || ('\n' == *s)) {
1440 s--;
1441 }
1442
1443 while (isspace((int) *s)) { /* remove blanks at end of line */
1444 s--;
1445 }
1446 *(s+1) = '\0';
1447
1448 return;
1449}
1450
1451
1452void restore_line(char *lin) { /* options (..) have been replaced by ..$ ! */
1453 while ('\0' != *lin) { /* restore line back to original if expand netlist */
1454 if ('$' == *lin) {
1455 *lin = ')';
1456 lin--;
1457 while (' ' != *lin) {
1458 lin--;
1459 }
1460 *lin = '(';
1461 }
1462 lin++;
1463 }
1464 return;
1465}
1466
1467
1468char *compact_line(char *str1, char *str2) { /* remove extra spaces */
1469 static char *s1 = (char*) NULL;
1470 static char *s2 = (char*) NULL;
1471 s1 = str1;
1472 s2 = str2;
1473 while (('\0' != *s1) && ('\0' != *(s1+1))) {
1474 if ((isspace((int) *s1)) && (isspace((int) *(s1+1)))) {
1475 s1++;
1476 } else {
1477 *s2 = *s1;
1478 s1++;
1479 s2++;
1480 }
1481 }
1482 *s2 = *s1;
1483 return str2;
1484}
1485
1486
1487char *extract_line(char *str1, char *str2) { /* str1 -> "abc..z\nABC...Z" */
1488 char *s1 = (char*) NULL; /* str1 -> "abc..z\\nABC...Z" */
1489 char *s2 = (char*) NULL;
1490 s1 = str1; /* s1 -> 'a' */
1491 s2 = str2;
1492 while ('\0' != *s1) {
1493 *s2 = *s1;
1494 if ('\n' == *s1) { /* detect '\n' (case "abc..z\nABC...Z" ) */
1495 break;
1496 }
1497 if (('\\' == *s1) && ('n' == *(s1+1))) { /* detect '\\n' (case "abc..z\\nABC...Z") */
1498 s1++;
1499 break;
1500 }
1501 s1++;
1502 s2++;
1503 }
1504 *s2 = '\0';
1505 str1 = s1 + 1; /* str1 -> 'A' */
1506 return str1;
1507}
1508
1509
1510void drop_filename(char *pnam) {
1511 char *sb = (char*) NULL;
1512 char *se = (char*) NULL;
1513 sb = pnam;
1514 se = pnam+ LENGTH(pnam);
1515 while (se != sb) {
1516 if ('/' == *se) {
1517 *se = '\0';
1518 return;
1519 }
1520 se--;
1521 }
1522 return;
1523}
1524
1525
1526void drop_pathname(char *pnam) {
1527 char *sb = (char*) NULL;
1528 char *se = (char*) NULL;
1529 sb = pnam;
1530 se = pnam+ LENGTH(pnam);
1531 while (se != sb) {
1532 if ('/' == *se) {
1533 (void) strcpy(pnam, 1 + se);
1534 return;
1535 }
1536 se--;
1537 }
1538 (void) strcpy(pnam, se); /* filename without pathname */
1539 return;
1540}
1541
1542
1543void simplify_pathname(char *pnam) {
1544 char *cur;
1545 char *t;
1546 int isrooted;
1547 char *very_start = pnam;
1548 char *start;
1549 if (!(*pnam)) {
1550 return;
1551 }
1552 isrooted = ('/' == pnam[0]);
1553 if (isrooted) {
1554 very_start++;
1555 }
1556 for (cur = t = start = very_start;;) { /* treat multiple '/'s as one '/' */
1557 while ('/' == *t) {
1558 t++;
1559 }
1560 if ('\0' == *t) {
1561 if (cur == pnam) { /* convert empty path to dot */
1562 *cur++ = '.';
1563 }
1564 *cur = '\0';
1565 break;
1566 }
1567 if ('.' == t[0]) {
1568 if ((!t[1]) || ('/' == t[1])) {
1569 t += 1;
1570 continue;
1571 } else if (('.' == t[1]) && ((!t[2]) || ('/' == t[2]))) {
1572 if ((!isrooted) && (cur == start)) {
1573 if (cur != very_start) {
1574 *cur++ = '/';
1575 }
1576 *cur++ = '.';
1577 *cur++ = '.';
1578 start = cur;
1579 } else if (cur != start) {
1580 while ((--cur > start) && ('/' != *cur));
1581 }
1582 t += 2;
1583 continue;
1584 }
1585 }
1586 if (cur != very_start) {
1587 *cur++ = '/';
1588 } /* find/copy next component of pathname */
1589 while ((*t) && ('/' != *t)) {
1590 *cur++ = *t++;
1591 }
1592 }
1593}
1594
1595
1596/* Remove name extension ( .xxx) from file name */
1597
1598void strip_extension(char *fnam) {
1599 char *s = (char*) NULL;
1600 char *t = (char*) NULL;
1601 long n;
1602 t = fnam;
1603 n = (LENGTH(t)) - 1L;
1604 s = t + n;
1605 while (0 < n) {
1606 if ('.' == *s) {
1607 *s = '\0';
1608 break; /* break as soon as one point is detected */
1609 }
1610 s--;
1611 n--;
1612 }
1613 return;
1614}
1615
1616
1617/* Remove double quotes from string */
1618
1619void strip_quotes(char *str) {
1620 char *s = (char*) NULL;
1621 char *t = (char*) NULL;
1622 s = str;
1623 t = str;
1624 if ('"' == *s) {
1625 s++;
1626 t++;
1627 }
1628 while ('\0' != *s) {
1629 if ('"' == *s) {
1630 *s = '\0';
1631 break;
1632 }
1633 s++;
1634 }
1635 (void) strcpy(str, t);
1636 return;
1637}
1638
1639
1640/* Replace '(..)' by '..$' in user functions to avoid collision with nodes or variables to avoid future collision between */
1641/* qualifiers and node or variable names. This is a temporary replacement which will be reworked when writing the C code. */
1642/* In option, a space as no meaning and will be removed here. */
1643
1644void replace_parentheses(char *str) { /* process a full line */
1645 char tok1[STRLENGTH] = {'\0'};
1646 char tok2[STRLENGTH] = {'\0'};
1647 char *t1 = (char*) NULL;
1648 char *t2 = (char*) NULL;
1649 int c;
1650 long n, l;
1651 int flag;
1652 flag = false; /* outside a string */
1653 l = LENGTH(str);
1654 t1 = tok1;
1655 t2 = tok2;
1656 for (c = 0; c < l; c++) {
1657 *(t1 + c) = *(str + c);
1658 }
1659 t1 = tok1;
1660 for (n = 0L; n < l; n++) {
1661 if (('"' != *t1) && (flag)) { /* inside a string, no process */
1662 t1++;
1663 continue;
1664 }
1665 if ('"' == *t1) {
1666 flag = (flag) ? false : true;
1667 t1++;
1668 continue;
1669 }
1670 if ('(' == *t1) {
1671 *t1 = ' ';
1672 }
1673 if (')' == *t1) {
1674 *t1 = '$';
1675 }
1676 t1++;
1677 }
1678 t1 = tok1;
1679 t2 = tok2;
1680 *t2 = *t1;
1681 t1++;
1682 t2++;
1683 *t2 = *t1;
1684 t1++;
1685 t2++;
1686 c = 0;
1687 while (l > c) { /* suppress space after :: */
1688 if (' ' != *t1) {
1689 *t2 = *t1;
1690 t1++;
1691 t2++;
1692 } else {
1693 if ((':' == *(t1-1)) && (':' == *(t1-2))) {
1694 t1++;
1695 } else {
1696 *t2 = *t1;
1697 t1++;
1698 t2++;
1699 }
1700 }
1701 c++;
1702 }
1703 t2 = tok2;
1704 for (c = 0; c < l; c++) {
1705 *(str + c) = *(t2 + c);
1706 }
1707 return;
1708}
1709
1710
1711/* Remove the '$' in '..$' for qualifier in user or tool functions */
1712
1713void replace_dollar(char *tok) { /* process a single token */
1714 long len;
1715 len = LENGTH(tok) - 1L;
1716 if ('$' == tok[len]) {
1717 tok[len] = '\0';
1718 }
1719 return;
1720}
1721
1722
1723/* format number in an engineering format with prefixes Y,Z,E,P,T,G,M,k, ,m,u,n,p,f,a,z,y */
1724
1725char *format_suffixed_number(double value, long places, const char *unit) {
1726 static char result[64] = {'\0'};
1727 const char prefixes[] = {'y', 'z', 'a', 'f', 'p', 'n', 'u', 'm', ' ', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'};
1728 long p_lo = 0L;
1729 long p = 8L;
1730 long p_hi = 16L;
1731 char sgn = ' ';
1732 if (0.0 > value) {
1733 sgn = '-';
1734 value = -value;
1735 }
1736 while ((p > p_lo) && ISNOTSMALL(value) && ( (1.0+_SMALL_) >= value)) {
1737 value *= 1000.0;
1738 p--;
1739 }
1740 while ((p < p_hi) && ISNOTSMALL(value) && (1000.0*(1.0-_SMALL_) <= value)) {
1741 value /= 1000.0;
1742 p++;
1743 }
1744 if (3L < places) {
1745 if (100.0*(1.0-_SMALL_) <= value) {
1746 places -= 3L;
1747 } else if ( 10.0*(1.0-_SMALL_) <= value) {
1748 places -= 2L;
1749 } else {
1750 places -= 1L;
1751 }
1752 (void) snprintf(result, (size_t) 63, "%c%.*f %c%s", sgn, (int) places, value, prefixes[p], unit);
1753 } else {
1754 if (100.0*(1.0-_SMALL_) <= value) {
1755 (void) snprintf(result, (size_t) 63, "%c%3.0f %c%s", sgn, value, prefixes[p], unit);
1756 } else if ( 10.0*(1.0-_SMALL_) <= value) {
1757 (void) snprintf(result, (size_t) 63, "%c%2.1f %c%s", sgn, value, prefixes[p], unit);
1758 } else {
1759 (void) snprintf(result, (size_t) 63, "%c%1.2f %c%s", sgn, value, prefixes[p], unit);
1760 }
1761 }
1762 return result;
1763}
1764
1765
1766char *unique_name(void) {
1767 static int count = 0;
1768 static char name[32];
1769 (void) snprintf(name, (size_t) 31, "%s_%d", NAPA_Job_ID, count);
1770 count++;
1771 return name;
1772}
1773
1774
1775char *upper_to_lower(char *s) {
1776 char *t = (char*) NULL;
1777 t = s;
1778 while ('\0' != *t) {
1779 if (isalpha((int) *t)) {
1780 *t = (char) tolower((int) *t);
1781 }
1782 t++;
1783 }
1784 return s;
1785}
1786
1787
1788char *replace_char(char *s, char b, char a) {
1789 char *t = (char*) NULL;
1790 t = s;
1791 while ('\0' != *t) {
1792 if (*t == b) {
1793 *t = a;
1794 }
1795 t++;
1796 }
1797 return s;
1798}
1799
1800
1801char *multiple(char c, long n) {
1802 int i, j;
1803 static char result[256] = {'\0'};
1804 char *s = (char*) NULL;
1805 s = result;
1806 j = MAX( 1L, n);
1807 j = MIN(255L, j);
1808 for (i = 0; i < j; i++) {
1809 *s = c;
1810 s++;
1811 }
1812 *s = '\0';
1813 return result;
1814}
1815
1816
1817int cistrcmp(const char *a, const char *b) { /* case insensitive strcmp() */
1818 int d;
1819 for (;; a++, b++) {
1820 d = (int) (tolower((unsigned char)*a) - tolower((unsigned char)*b));
1821 if ((0 != d) || (!(*a))) {
1822 return d;
1823 }
1824 }
1825}
1826
1827
1828int fnstrcmp(char const *a, char const *b) { /* file name strcmp() compare depending on OS */
1829 int d;
1830 for (;; a++, b++) {
1831#if (IS_WIN64 == PLATFORM)
1832 d = (int) (tolower((unsigned char)*a) - tolower((unsigned char)*b));
1833#else
1834 d = (int) (*a - *b);
1835#endif
1836 if ((0 != d) || (!(*a))) {
1837 return d;
1838 }
1839 }
1840}
1841
1842
1843int f1flush(FILE *fp) {
1844 if ((FILE*) NULL != fp) {
1845 if (EOF == fflush(fp)) {
1846 print_error_location("I/O", (unsigned long*) NULL, (unsigned long*) NULL);
1847 (void) fprintf(STDERR, " Flushing data from buffers I/O was not successful\n");
1849 }
1850 }
1851 return 0;
1852}
1853
1854
1855/* ****************************************************************************************************************************** */
1856/* end of file */
void print_error_location(const char *type, const unsigned long *mlin, const unsigned long *mfil)
Definition fc.c:1476
void print_limits(void)
Definition fc.c:56
long constant_type(char *identifier)
Definition id.c:1130
long get_type(char *identifier)
Definition id.c:1190
long array_id(const char *identifier)
Definition id.c:635
long directive_id(const char *identifier)
Definition id.c:707
long node_id(const char *identifier)
Definition id.c:718
long var_id(const char *identifier)
Definition id.c:855
long record_id(const char *identifier)
Definition id.c:796
EXTERN char Inst_Plist[31L][127L][16383L]
Definition napa.h:937
#define RIGHT_VALUE
Definition napa.h:416
EXTERN RANDOMSEED_TYPE Seed_List
Definition napa.h:979
EXTERN VAR_TYPE Var_List[2047L]
Definition napa.h:970
EXTERN RECORD_TYPE Record_List[127L]
Definition napa.h:965
#define _SMALL_
Definition napa.h:146
EXTERN ARRAY_TYPE Array_List[63L]
Definition napa.h:950
#define LENGTH(s)
Definition napa.h:397
EXTERN char Cell_Name_Prefix[31L][2047L]
Definition napa.h:945
#define UNDEFINED
Definition napa.h:331
#define STDERR
Definition napa.h:105
EXTERN NODE_TYPE Node_List[4095L]
Definition napa.h:962
EXTERN char NAPA_Job_ID[19]
Definition napa.h:993
#define ANALOG_DATA_TYPE
Definition napa.h:338
EXTERN SAMPLING_TYPE Sampling_List
Definition napa.h:978
EXTERN DIRECTIVE_TYPE Directive_List[255L]
Definition napa.h:955
#define LINLENGTH
Definition napa.h:216
#define MIN(x, y)
Definition napa.h:376
EXTERN char Cur_Lib_Name[31L][2047L]
Definition napa.h:932
EXTERN long Cell_Num_Parms[31L]
Definition napa.h:934
#define ISNOTEMPTY(s)
Definition napa.h:395
#define MAX(x, y)
Definition napa.h:377
#define STRLENGTH
Definition napa.h:217
#define ISEMPTY(s)
Definition napa.h:394
#define STRING_DATA_TYPE
Definition napa.h:339
#define HEX_DATA_TYPE
Definition napa.h:340
#define ISNOTSMALL(x)
Definition napa.h:385
EXTERN char Cell_Plist[31L][127L][16383L]
Definition napa.h:936
#define DIGITAL_DATA_TYPE
Definition napa.h:337
EXTERN int Periodic_Flag
Definition napa.h:873
void print_error_banner_and_exit(void)
Definition pr.c:5482
char * expand_nodeset(char *str, long n, long w, const unsigned long *mlin, const unsigned long *mfil)
Definition tk.c:969
int cistrcmp(const char *a, const char *b)
Definition tk.c:1817
char * unique_name(void)
Definition tk.c:1766
void extract_directory(char *pn, char *fn, long depth)
Definition tk.c:339
void build_pathname(const char *brc, char *tok, const char *path, const unsigned long *mlin, const unsigned long *mfil)
Definition tk.c:230
void replace_parentheses(char *str)
Definition tk.c:1644
int is_an_extended_identifier(const char *tok)
Definition tk.c:1348
char * extract_line(char *str1, char *str2)
Definition tk.c:1487
char * upper_to_lower(char *s)
Definition tk.c:1775
void strip_extension(char *fnam)
Definition tk.c:1598
char * replace_char(char *s, char b, char a)
Definition tk.c:1788
char * extract_prefix(char *nam)
Definition tk.c:1086
char * get_token(char *str, char *tok, long keep_quotes)
Definition tk.c:1210
void clean_line(char *str)
Definition tk.c:1397
char * build_name(const char *sgn, char *tok, long lr_type)
Definition tk.c:69
int fnstrcmp(char const *a, char const *b)
Definition tk.c:1828
void process_cell_line(char *buf, long d, const unsigned long *mlin, const unsigned long *mfil)
Definition tk.c:441
void clean_parentheses(char *tok)
Definition tk.c:403
void restore_line(char *lin)
Definition tk.c:1452
int f1flush(FILE *fp)
Definition tk.c:1843
void resolve_pathnames(char *lin, long depth)
Definition tk.c:265
void expand_iterative_identifiers(char *str, unsigned long *mlin, const unsigned long *mfil)
Definition tk.c:796
int is_a_string(char *str)
Definition tk.c:1369
char * compact_line(char *str1, char *str2)
Definition tk.c:1468
char * get_output_and_scaling(char *str, char *sgn, char *out, char *scl)
Definition tk.c:1061
int is_an_integer_number(const char *str)
Definition tk.c:1378
int is_an_identifier(const char *tok)
Definition tk.c:1327
char * multiple(char c, long n)
Definition tk.c:1801
char * get_function_identifier(char *str, char *fun_id, char *fun_parm)
Definition tk.c:1036
void strip_quotes(char *str)
Definition tk.c:1619
void replace_dollar(char *tok)
Definition tk.c:1713
char * get_token_between_braces(char *str, char *brc, char *tok)
Definition tk.c:1110
void expand_indirections(char *str)
Definition tk.c:717
void simplify_pathname(char *pnam)
Definition tk.c:1543
void drop_pathname(char *pnam)
Definition tk.c:1526
char * format_suffixed_number(double value, long places, const char *unit)
Definition tk.c:1725
char * get_sign_and_token(char *str, char *sgn, char *tok)
Definition tk.c:1188
void drop_filename(char *pnam)
Definition tk.c:1510