1 /****************************************************************************
2 Copyright (C) 1987-2015 by Jeffery P. Hansen
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
18 Last edit by hansen on Sun Feb 8 19:30:29 2009
19 ****************************************************************************/
20 #include "thyme.h"
21
22 /*****************************************************************************
23 *
24 * When warning_mode is 2, we want to display warnings only if there were
25 * errors. This means we need to defer display of warnings until we see an
26 * error. The following structure is used for this purpose.
27 *
28 *****************************************************************************/
29 typedef struct DeferedWarning_str DeferedWarning;
30 struct DeferedWarning_str {
31 char *dw_msg;
32 DeferedWarning *dw_next;
33 };
34 DeferedWarning *wdefer_head = 0;
35 DeferedWarning *wdefer_tail = 0;
36
37 extern Place curPlace;
38 static placemode_t placeMode = (placemode_t)(PM_FILE|PM_LINE|PM_PRETTY);
39 char *current_script = 0;
40 int warning_mode = 3;
41
42 /*****************************************************************************
43 *
44 * Table of error messages.
45 *
46 * Each error message has a tag, and a text message associated with it. When
47 * thyme is running in interactive mode, the tags are used, and when running
48 * in stand alone mode, the full messages are used. The tags are used in interactive
49 * mode to allow translation through a tkgate messages file. The English message
50 * table in messages format can be generated by running the simulator with the -e switch.
51 *
52 *****************************************************************************/
53 static ErrorDescriptor errorTable[] = {
54 {ERR_OK, 0, "OK", "Don't worry, be happy."},
55 {WRN_INPORT, 0, "INPORT", "Port size mismatch on input port '%s'."},
56 {WRN_OUTPORT, 0, "OUTPORT", "Port size mismatch on output port '%s'."},
57 {WRN_FLOATNET, 0, "FLOATNET", "Net '%s' has no drivers (floating net)."},
58 {WRN_DIRECTCONN, 0, "DIRECTCONN", "Direct connect operator '=>' unsupported. Treated as '*>'."},
59 {ERR_MEMADDR, 1, "MEMADDR", "Attempt to write to memory %s with unknown address."},
60 {ERR_MEMBITS, 1, "MEMBITS", "Attempt to write to memory %s with unknown bitrange."},
61 {ERR_BADARRAYUSG, 1, "BADARRAYUSG", "Array '%s' used in expression without index."},
62 {ERR_BADARRAYLHS, 1, "BADARRAYLHS", "Array '%s' used without index on left-hand-side."},
63 {ERR_BADCLOSE, 1, "BADCLOSE", "Attempt to close non-open descriptor in task '%s'."},
64 {ERR_BADAUTORNG, 1, "BADAUTORNG", "Auto range [*] is only valid with 'wire' declaration."},
65 {ERR_BADGATERNG, 1, "BADGATERNG", "Bad gate instance range expression."},
66 {ERR_DIVZERO, 1, "DIVZERO", "Divide by zero."},
67 {ERR_BADEDGEEVENT, 1, "BADEDGEEVENT", "Event on multi-bit net '%s' can not have posedge/negedge."},
68 {ERR_NEEDEDGE, 1, "NEEDEDGE", "Must specify posedge or negedge on event for %s."},
69 {ERR_ASGNEVENT, 1, "ASGNEVENT", "Event wait on assign is illegal."},
70 {ERR_PROTTASK, 1, "PROTTASK", "Execution of protected system task '%s' blocked."},
71 {ERR_NEEDIDENT, 1, "NEEDIDENT", "Expecting identifier for argument %s of task '%s'."},
72 {ERR_BADOP, 1, "BADOP", "Expression operator error in '%s'."},
73 {ERR_NOREAD, 1, "NOREAD", "Failed to load source file '%s'."},
74 {ERR_MEMFILE, 1, "MEMFILE", "Failed to open memory file '%s'."},
75 {ERR_WRONGMOD, 1, "WRONGMOD", "Found module '%s' when expecting '%s'."},
76 {ERR_NOTPARM, 1, "NOTPARM", "Identifier '%s' in constant expression is not a parameter."},
77 {ERR_BADADDR, 1, "BADADDR", "Illegal address range on port '%s'."},
78 {ERR_BADADDRSPEC, 1, "BADADDRSPEC", "Illegal address range specification '%s'."},
79 {ERR_BADCHAR, 1, "BADCHAR", "Illegal character (%s) '%s'."},
80 {ERR_BADEVENT, 1, "BADEVENT", "Illegal event control expression."},
81 {ERR_BADCONSTOP, 1, "BADCONSTOP", "Illegal operator in constant expression."},
82 {ERR_BADXOP, 1, "BADXOP", "Illegal operator in expression."},
83 {ERR_NETREDEF, 1, "NETREDEF", "Illegal redefinition of net '%s'."},
84 {ERR_BADINOUT, 1, "BADINOUT", "Inout connections must be net-to-net on port '%s'."},
85 {ERR_MODUNDEF, 1, "MODUNDEF", "Instance of undefined module '%s'."},
86 {ERR_BADASGNLHS, 1, "BADASGNLHS", "Invalid left-hand-side in 'assign'."},
87 {ERR_LHSNOTREG, 1, "LHSNOTREG", "Illegal use of '%s' in left-hand-side of assignment."},
88 {ERR_BADLHS, 1, "BADLHS", "Invalid left-hand-side in assignment."},
89 {ERR_BADOUT, 1, "BADOUT", "Invalid output assignment."},
90 {ERR_NOTREG, 1, "NOTREG", "Memories must be declared as register."},
91 {ERR_PORTMIX, 1, "PORTMIX", "Mixed named and unnamed ports on interface '%s' of '%s'."},
92 {ERR_REPCASE, 1, "REPCASE", "More than one default: in case statement."},
93 {ERR_NOMEM, 1, "NOMEM", "No current memory in memory file read."},
94 {ERR_BADCMD, 1, "BADCMD", "No such command '%s'."},
95 {ERR_CMDNOTNET, 1, "CMDNOTNET", "No such net '%s' in '%s' command."},
96 {ERR_MEMNONBLK, 1, "MEMNONBLK", "Non-blocking assignments to memories not implemented."},
97 {ERR_NOTPPORT, 1, "NOTPPORT", "Parameter '%s' is not declared as a port."},
98 {ERR_REDEFP, 1, "REDEFP", "Parameter redefines identifier '%s'."},
99 {ERR_PORTNOTDEF, 1, "PORTNOTDEF", "Port '%s' on interface '%s' is not defined in module '%s'."},
100 {ERR_NOCONN, 1, "NOCONN", "Port '%s' has no connections on interface '%s' of '%s'."},
101 {ERR_MULTCONN, 1, "MULTCONN", "Port '%s' has multiple connections on interface '%s' of '%s'."},
102 {ERR_PORTCOUNT, 1, "PORTCOUNT", "Port count does not match definition on interface '%s' of '%s'."},
103 {ERR_BADPRTRANGE, 1, "BADPRTRANGE", "Range on port '%s' is not numeric."},
104 {ERR_BADARRAYRNG, 1, "BADARRAYRNG", "Range specification not allowed for memory reference of '%s'."},
105 {ERR_CMDMODREDEF, 1, "CMDMODREDEF", "Redefinition of dynamic module '%s'."},
106 {ERR_REDEF, 1, "REDEF", "Redefinition of identifier '%s'."},
107 {ERR_PROTTASKSTOP, 1, "PROTTASKSTOP", "Simulation stopped on attempted execution of protected system task '%s'."},
108 {ERR_NOTMEM, 1, "NOTMEM", "Specified net '%s' is not a memory."},
109 {ERR_CMDNOTMEM, 1, "CMDNOTMEM", "Specified net '%s' is not a memory in '%s' command."},
110 {ERR_SYNTAX, 1, "SYNTAX", "Syntax error."},
111 {ERR_BADHIER, 1, "BADHIER", "Hierarchical variable '%s' referenced in illegal context."},
112 {ERR_TOOFEWPP, 1, "TOOFEWPP", "Too few parameter ports on instance %s."},
113 {ERR_OPENTOOMANY, 1, "OPENTOOMANY", "Too many files open in task '%s'."},
114 {ERR_TOOMANYPP, 1, "TOOMANYPP", "Too many parameter ports on instance %s."},
115 {ERR_NOTOP, 1, "NOTOP", "Top-module '%s' not defined."},
116 {ERR_BADOPEN, 1, "BADOPEN", "Unable to open output file '%s' in task '%s'."},
117 {ERR_CMDNOMOD, 1, "CMDNOMOD", "Undefined dynamic module '%s' in '%s' command."},
118 {ERR_BADEVENTNET, 1, "BADEVENTNET", "Undefined net '%s' in event control expression."},
119 {ERR_NOTASK, 1, "NOTASK", "Undefined task '%s'."},
120 {ERR_NOTDEF, 1, "NOTDEF", "Undefined variable '%s'."},
121 {ERR_BADRANGE, 1, "BADRANGE", "Unsupported bit range [%s] on net %s (must be of form [n:0])."},
122 {ERR_GATEUNIMP, 1, "GATEUNIMP", "Unimplemented primitive component type on instance '%s'."},
123 {ERR_USAGE, 1, "USAGE", "Usage: verga [options][files...]"},
124 {ERR_CLSDWRITE, 1, "CLSDWRITE", "Write to closed descriptor."},
125 {ERR_PRIMPTCOUNT, 1, "PRIMPTCOUNT", "Wrong number of ports on primitive gate instance '%s'."},
126 {ERR_CMDARGS, 1, "CMDARGS", "Wrong number of arguments in '%s' command."},
127 {ERR_YYERROR, 1, "YYERROR", "YYError - %s."},
128 {ERR_TASKARGS, 1, "TASKARGS", "Task '%s' called with wrong number of arguments."},
129 {ERR_BADSTART, 1, "BADSTART", "Illegal start value in task '%s'."},
130 {ERR_BADSTOP, 1, "BADSTOP", "Illegal stop value in $readmemb."},
131 {ERR_SPECTASKUSG, 1, "SPECTASKUSG", "Task %s must be used in a specify block."},
132 {ERR_BADSPECTASK, 1, "BADSPECTASK", "Task %s can not be used in a specify block."},
133 {ERR_TIMING, 1, "TIMING", "Timing violation in %s[%s] %s."},
134 {ERR_NOIFDEF, 1, "NOIFDEF", "No matching `ifdef/`ifndef for %s declaration."},
135 {ERR_BADSPECLVAL, 1, "BADSPECLVAL", "Bit-ranges on path delay specifiers unsupported."},
136 {ERR_PATHDMEM, 1, "PATHDMEM", "Illegal declaration of memory '%s' in path-delay module - unsupported."},
137 {ERR_PATHDINOUT, 1, "PATHDINOUT", "Use of 'inout' in module with path-delay specification is unsupported."},
138 {ERR_PATHDLOOP, 1, "PATHDLOOP", "Loops in path-delay modules are unsupported."},
139 {ERR_PATHDREASSGN, 1, "PATHDREASSGN", "Multiple assignment of net '%s' in path-delay module is unsupported."},
140 {ERR_PATHDNOTIN, 1, "PATHDNOTIN", "Net '%s' has no driver and is not an input in path-delay module."},
141 {ERR_PATHDCOND, 1, "PATHDCOND", "Delay and trigger expressions not allowed in path-delay modules."},
142 {ERR_TASKREDEF, 1, "TASKREDEF", "Redefinition of task or function '%s' in module '%s'."},
143 {ERR_TASKASFUNC, 1, "TASKASFUNC", "Task '%s' used as function."},
144 {ERR_FUNCASTASK, 1, "FUNCASTASK", "Function '%s' used as task."},
145 {ERR_TASKBADTYPE, 1, "TASKBADTYPE", "Non-register type used in task or function."},
146 {ERR_TASKBADPORT, 1, "TASKBADPORT", "Only input ports are allowed on functions."},
147 {ERR_TIMESCALEU, 1, "TIMESCALEU", "Invalid units '%s' in `timescale declaration."},
148 {ERR_TIMESCALEN, 1, "TIMESCALEN", "Invalid scale '%s' in `timescale declaration (must be 1, 10 or 100)."},
149 {ERR_TIMESCALES, 1, "TIMESCALES", "Invalid syntax in `timescale declartion."},
150 {ERR_TIMESCALEX, 1, "TIMESCALEX", "Units must be larger than precision in `timescale declartion."},
151 {ERR_TIMESCALEAN, 1, "TIMESCALEAN", "Design contains some modules with `timescale and some without."},
152 {ERR_PARAMMIX, 1, "PARAMMIX", "Mixed named and unnamed parameters on interface '%s' of '%s'."},
153 {ERR_BADPORTTYPE, 1, "BADPORTTYPE", "Invalid type declaration used on port '%s'."},
154 {ERR_BADVALUE, 1, "BADVALUE", "Bad numeric value '%s'."},
155 {ERR_NONEXPCTL, 1, "NONEXPCTL", "Event control @(*) applied to non-expression."},
156 {ERR_NONSTATCTL, 1, "NONSTATCTL", "Event control @(*) applied to non-statement."},
157
158 {ERR_MODREDEF, 1, "MODREDEF", "Redefinition of module '%s'."},
159 {ERR_IE_TASK, 1, "IE_TASK", "Task definition '%s' found outside module - internal error."},
160 {ERR_IE_NONET, 1, "IE_NONET", "Failed to find net '%s' - internal error."},
161 {ERR_IE_NOOP, 1, "IE_NOOP", "Can not find operator description -- internal error."},
162 {ERR_IE_BADEXP, 1, "IE_BADEXP", "Unexpected expression type %s - internal error."},
163 {ERR_IE_BADVAR, 1, "IE_BADVAR", "Undefined variable or unknown net - internal error."},
164 {ERR_IE_BADSTATE, 1, "IE_BADSTATE", "Unexpected internal state at %s - internal error."},
165 {ERR_IE_RETURN, 1, "IE_RETURN", "Executed BCReturn bytecode with empty return stack - internal error."},
166 {ERR_IE_UNIMP, 1, "IE_UNIMP", "Unimplemented feature."},
167 };
168 static int errorTableLen = sizeof(errorTable)/sizeof(errorTable[0]);
169
170 static ErrorDescriptor unknownError = {
171 ERR_UNKNOWN, 1, "UNKNOWN", "Unknown error message."
172 };
173
174 #define EL_SCRIPTERR 2
175 static char *errLevelText[] = {"warning", "error", "scripterror"};
176 static char *errLevelTextCap[] = {"Warning", "Error", "ScriptError"};
177
178 /*****************************************************************************
179 *
180 * Array for used to temporarily store arguments for an error message. The
181 * array is initialized by initErrorMessages() and has a length equal to the
182 * maximum number of arguments in any error message in the error message table.
183 *
184 *****************************************************************************/
185 static char **errArgs;
186
187 /*****************************************************************************
188 *
189 * Initialize the error table by counting the number of arguments to each message.
190 *
191 *****************************************************************************/
initErrorMessages()192 void initErrorMessages()
193 {
194 int i;
195 int maxCount = 0;
196
197 for (i = 0;i < errorTableLen;i++) {
198 ErrorDescriptor *ed = &errorTable[i];
199 char *p;
200 int count = 0;
201
202
203 for (p = ed->ed_text;*p;p++) {
204 if (*p == '%') {
205 if (p[1] == '%')
206 p++;
207 else
208 count++;
209 }
210 }
211
212 if (count > maxCount) maxCount = count;
213
214 ed->ed_numArgs = count;
215 }
216
217 errArgs = (char**)malloc(sizeof(char*)*maxCount);
218 }
219
flushDefered()220 void flushDefered()
221 {
222 while (wdefer_head) {
223 DeferedWarning *dw = wdefer_head;
224 wdefer_head = wdefer_head->dw_next;
225 free(dw->dw_msg);
226 free(dw);
227 }
228
229 wdefer_head = 0;
230 wdefer_tail = 0;
231 }
232
flushErrors()233 void flushErrors()
234 {
235 extern int errCount;
236 extern int warnCount;
237
238 errCount = 0;
239 warnCount = 0;
240 flushDefered();
241 }
242
deferWarning(const char * msg)243 void deferWarning(const char *msg)
244 {
245 DeferedWarning *dw = (DeferedWarning*) malloc(sizeof(DeferedWarning));
246
247 dw->dw_msg = strdup(msg);
248 dw->dw_next = 0;
249
250 if (wdefer_tail) {
251 wdefer_tail->dw_next = dw;
252 wdefer_tail = dw;
253 } else {
254 wdefer_head = wdefer_tail = dw;
255 }
256 }
257
reportDeferedWarnings()258 void reportDeferedWarnings()
259 {
260 DeferedWarning *dw;
261
262 for (dw = wdefer_head;dw;dw = dw->dw_next)
263 vgio_printf("%s\n",dw->dw_msg);
264 flushDefered();
265 }
266
267 /*****************************************************************************
268 *
269 * Dump the list of error messages in tkgate messages format.
270 *
271 *****************************************************************************/
dumpErrorMessages()272 void dumpErrorMessages()
273 {
274 int i;
275
276 for (i = 0;i < errorTableLen;i++) {
277 ErrorDescriptor *ed = &errorTable[i];
278 int l = strlen(ed->ed_tag) + 10;
279
280 printf("verga.err.%s",ed->ed_tag);
281
282 l = l/8 + 1;
283
284 for (;l < 4;l++)
285 printf("\t");
286
287 printf("\t%s\n",ed->ed_text);
288 }
289 }
290
291 /*****************************************************************************
292 *
293 * Find the error message descriptor for the error with the given code.
294 *
295 * Parameters:
296 * ecode Code number of message to find.
297 *
298 * Returns: Error descriptor corresponding to the given error code.
299 * Returns a special "unknown" error descriptor if the
300 * specified code is not found.
301 *
302 *****************************************************************************/
findError(errorcode_t ecode)303 static ErrorDescriptor *findError(errorcode_t ecode)
304 {
305 int i;
306
307 for (i = 0;i < errorTableLen;i++)
308 if (errorTable[i].ed_code == ecode)
309 return &errorTable[i];
310
311 return &unknownError;
312 }
313
314 /*****************************************************************************
315 *
316 * Initialize the a place to the beginning of a file.
317 *
318 * Parameters:
319 * p Place to be initialized
320 * fileName Name of file.
321 *
322 *****************************************************************************/
Place_init(Place * p,const char * fileName)323 void Place_init(Place *p, const char *fileName)
324 {
325 p->p_fileName = fileName ? strdup(fileName) : 0;
326 p->p_moduleName = 0;
327 p->p_mitem = 0;
328 p->p_lineNo = 1;
329 p->p_modLineNo = 0;
330 p->p_mtag = 0;
331 }
332
333 /*****************************************************************************
334 *
335 * Copy a place.
336 *
337 * Parameters:
338 * dstP Destination place
339 * srcP Source place
340 *
341 *****************************************************************************/
Place_copy(Place * dstP,Place * srcP)342 void Place_copy(Place *dstP, Place *srcP)
343 {
344 *dstP = *srcP;
345 }
346
347 /*****************************************************************************
348 *
349 * Increment the line number of a place
350 *
351 * Parameters:
352 * p Place to be updated
353 * delta Number of lines to add to place.
354 *
355 *****************************************************************************/
Place_incLineno(Place * p,int delta)356 void Place_incLineno(Place *p, int delta)
357 {
358 p->p_lineNo += delta;
359 p->p_modLineNo += delta;
360 }
361
362 /*****************************************************************************
363 *
364 * Indicate current place is in a module
365 *
366 * Parameters:
367 * p Place to be updated
368 * modName Name of module
369 *
370 *****************************************************************************/
Place_startModule(Place * p,const char * modName)371 void Place_startModule(Place *p, const char *modName)
372 {
373 if (!p->p_mtag) {
374 p->p_moduleName = modName ? strdup(modName) : 0;
375 p->p_modLineNo = 1;
376 }
377 }
378
379 /*****************************************************************************
380 *
381 * Indicate current place is outside a module
382 *
383 * Parameters:
384 * p Place to be updated
385 *
386 *****************************************************************************/
Place_endModule(Place * p)387 void Place_endModule(Place *p)
388 {
389 if (!p->p_mtag) {
390 p->p_moduleName = 0;
391 p->p_modLineNo = 1;
392 }
393 }
394
395 /*****************************************************************************
396 *
397 * Indicate current place is inside a tag defined module
398 *
399 * Parameters:
400 * p Place to be updated
401 *
402 *****************************************************************************/
Place_startMTag(Place * p,const char * modName)403 void Place_startMTag(Place *p, const char *modName)
404 {
405 p->p_moduleName = modName ? strdup(modName) : 0;
406 p->p_modLineNo = 1;
407 p->p_mtag = 1;
408 }
409
410 /*****************************************************************************
411 *
412 * Indicate current place is outside a tag defined module
413 *
414 * Parameters:
415 * p Place to be updated
416 *
417 *****************************************************************************/
Place_endMTag(Place * p)418 void Place_endMTag(Place *p)
419 {
420 p->p_moduleName = 0;
421 p->p_modLineNo = 1;
422 p->p_mtag = 0;
423 }
424
425 /*****************************************************************************
426 *
427 * Generate string encoding a "place".
428 *
429 * Parameters:
430 * p Place to encode
431 * etype Error message type
432 * s Buffer to write encoding to.
433 *
434 * Returns: Pointer to end of encoded string in buffer.
435 *
436 *
437 *****************************************************************************/
Place_report(Place * p,const char * etype,const char * netName,char * s)438 char *Place_report(Place *p, const char *etype, const char *netName,char *s)
439 {
440 int did_first = 0;
441
442 if ((placeMode & PM_PRETTY)) {
443 if (strcmp(etype,"warning") == 0)
444 s += sprintf(s,"Warning: ");
445
446 *s++ = '<';
447 if ((placeMode & PM_FILE)) {
448 s += sprintf(s, "\"%s\"",p->p_fileName);
449 did_first = 1;
450 }
451 if ((placeMode & PM_LINE)) {
452 if (did_first) s += sprintf(s, ", ");
453 s += sprintf(s, "%d",p->p_lineNo);
454 did_first = 1;
455 }
456 if ((placeMode & PM_MODULE)) {
457 if (did_first) s += sprintf(s, ", ");
458 s += sprintf(s, "[%s]",(p->p_moduleName ? p->p_moduleName : "-"));
459 }
460 if ((placeMode & PM_MODLINE))
461 s += sprintf(s, "+%d",p->p_modLineNo);
462
463 *s++ = '>';
464 *s++ = ' ';
465 } else {
466 s += sprintf(s,"%s file",etype);
467 if ((placeMode & PM_FILE))
468 s += sprintf(s, " %s",p->p_fileName);
469 if ((placeMode & PM_LINE))
470 s += sprintf(s, " %d",p->p_lineNo);
471 if ((placeMode & PM_MODULE))
472 s += sprintf(s, " %s",(p->p_moduleName ? p->p_moduleName : "-"));
473 if ((placeMode & PM_MODLINE))
474 s += sprintf(s, " %d",p->p_modLineNo);
475 if (p->p_mitem && ModuleItem_getType(p->p_mitem) == IC_INSTANCE && !(placeMode & PM_PRETTY))
476 s += sprintf(s," %s",p->p_mitem->mi_inst.mii_instName);
477 else
478 s += sprintf(s," -");
479
480 if (netName)
481 s += sprintf(s," %s",netName);
482 else
483 s += sprintf(s," -");
484
485 s += sprintf(s," : ");
486 }
487
488 *s = 0;
489 return s;
490 }
491
492 /*****************************************************************************
493 *
494 * Set the mode for place display
495 *
496 * Parameters:
497 * pm Place display mode.
498 *
499 *****************************************************************************/
Place_setMode(placemode_t pm)500 void Place_setMode(placemode_t pm)
501 {
502 placeMode = pm;
503 }
504
505 /*****************************************************************************
506 *
507 * Reset the module line number
508 *
509 * Parameters:
510 * p Place to update
511 *
512 *****************************************************************************/
Place_resetModLine(Place * p)513 void Place_resetModLine(Place *p)
514 {
515 p->p_modLineNo = 0;
516 }
517
518
519 /*****************************************************************************
520 *
521 * Set the "current" place.
522 *
523 * Parameters:
524 * p Place to use as current place
525 *
526 *****************************************************************************/
Place_setCurrent(Place * p)527 void Place_setCurrent(Place *p)
528 {
529 curPlace = *p;
530 }
531
532 /*****************************************************************************
533 *
534 * Get the "current" place.
535 *
536 *****************************************************************************/
Place_getCurrent()537 Place *Place_getCurrent()
538 {
539 return &curPlace;
540 }
541
542 /*****************************************************************************
543 *
544 * Report built-in parser errors
545 *
546 * Parameters:
547 * err Text of error message
548 *
549 * This function must be supported by programs using yacc. It is only called
550 * from within built-in yacc code. The most common message is "syntax error"
551 * and if we see this message, we translate it to ERR_SYNTAX to allow localization
552 * if necessary.
553 *
554 *****************************************************************************/
yyerror(char * err)555 int yyerror(char *err)
556 {
557 if (strncmp(err,"syntax",6) == 0)
558 errorFile(Place_getCurrent(),ERR_SYNTAX);
559 else
560 errorFile(Place_getCurrent(),ERR_YYERROR,err);
561
562 return 0;
563 }
564
565 /*****************************************************************************
566 *
567 * Marshal a string so that it can be read as a tcl string.
568 *
569 * Parameters:
570 * p Marshaled string
571 * s String to be marshaled
572 *
573 *****************************************************************************/
marshalString(char * p,char * s)574 static int marshalString(char *p,char *s)
575 {
576 char *start = p; // Remeber start of marshaled string
577
578 /* Leading quote */
579 *p++ = '"';
580
581 for (;*s;s++) {
582 if (strchr("\\\"",*s))
583 *p++ = '\\';
584 *p++ = *s;
585 }
586
587 /* Trailing quote */
588 *p++ = '"';
589 return p-start;
590 }
591
592 /*****************************************************************************
593 *
594 * Format an error message
595 *
596 *****************************************************************************/
formatErrorMsg(char * p,ErrorDescriptor * ed,va_list ap)597 static int formatErrorMsg(char *p,ErrorDescriptor *ed,va_list ap)
598 {
599 if (vgsim.vg_interactive) {
600 int i;
601 char *q = p;
602
603 p += sprintf(p,"`%s",ed->ed_tag);
604 for (i = 0;i < ed->ed_numArgs;i++) {
605 p += sprintf(p," ");
606 p += marshalString(p,va_arg(ap,char*));
607 }
608 *p = 0;
609 return p-q;
610 } else {
611 return vsprintf(p,ed->ed_text,ap);
612 }
613
614 return 0;
615 }
616
617 /*****************************************************************************
618 *
619 * Handle the output of error (or warning) message text.
620 *
621 * Parameters:
622 * ed Error type descriptor
623 * msg Text of the error message.
624 *
625 *****************************************************************************/
doErrorOutput(ErrorDescriptor * ed,const char * msg)626 static void doErrorOutput(ErrorDescriptor *ed,const char *msg)
627 {
628 extern int errCount;
629 extern int warnCount;
630
631 if (ed->ed_level > 0) {
632 errCount++;
633 reportDeferedWarnings(); /* Report any defered warnings */
634 vgio_printf("%s\n",msg);
635 } else {
636 if (warning_mode > 1) {
637 warnCount++;
638 if (warning_mode == 2 && errCount == 0)
639 deferWarning(msg);
640 else
641 vgio_printf("%s\n",msg);
642 }
643 }
644
645 }
646
647 /*****************************************************************************
648 *
649 * Generate a command error
650 *
651 * Parameters:
652 * ecode Error code value
653 * ... Error-specific arguments
654 *
655 *****************************************************************************/
errorCmd(errorcode_t ecode,...)656 void errorCmd(errorcode_t ecode,...)
657 {
658 ErrorDescriptor *ed = findError(ecode);
659 char buf[STRMAX],*p;
660 va_list ap;
661 extern int errCount;
662
663 p = buf;
664 if (vgsim.vg_interactive)
665 p += sprintf(p,"%s command ",errLevelText[ed->ed_level]);
666 else
667 p += sprintf(p,"Command %s: ",errLevelTextCap[ed->ed_level]);
668
669 va_start(ap,ecode);
670 p += formatErrorMsg(p,ed,ap);
671 va_end(ap);
672
673 doErrorOutput(ed,buf);
674
675 errCount++;
676 }
677
678 /*****************************************************************************
679 *
680 * Generate a runtime error
681 *
682 * Parameters:
683 * ecode Error code value
684 * ... Error-specific arguments
685 *
686 *****************************************************************************/
errorRun(errorcode_t ecode,...)687 void errorRun(errorcode_t ecode,...)
688 {
689 ErrorDescriptor *ed = findError(ecode);
690 char buf[STRMAX],*p;
691 va_list ap;
692 EvQueue *Q = Circuit_getQueue(&vgsim.vg_circuit);
693 simtime_t curTime = EvQueue_getCurTime(Q);
694
695 p = buf;
696 if (vgsim.vg_interactive)
697 p += sprintf(p,"%s run %llu : ",errLevelText[ed->ed_level],curTime);
698 else
699 p += sprintf(p,"Runtime %s at %llu: ",errLevelTextCap[ed->ed_level],curTime);
700
701 va_start(ap,ecode);
702 p += formatErrorMsg(p,ed,ap);
703 va_end(ap);
704
705 doErrorOutput(ed,buf);
706 }
707
708 /*****************************************************************************
709 *
710 * Generate a file error
711 *
712 * Parameters:
713 * place Place identifier for location of the error.
714 * ecode Error code value
715 * ... Error-specific arguments
716 *
717 *****************************************************************************/
errorFile(Place * place,errorcode_t ecode,...)718 void errorFile(Place *place,errorcode_t ecode,...)
719 {
720 ErrorDescriptor *ed = findError(ecode);
721 char message[STRMAX],*p;
722 va_list ap;
723 extern int errCount;
724 extern int warnCount;
725
726 p = message;
727
728 if (current_script)
729 p += sprintf(p,"scripterror %s %s %d : ",current_script,place->p_fileName,place->p_lineNo+1);
730 else
731 p = Place_report(place,errLevelText[ed->ed_level],0,message);
732
733 va_start(ap,ecode);
734 p += formatErrorMsg(p,ed,ap);
735 va_end(ap);
736 doErrorOutput(ed,message);
737
738 #if 0
739 if (!script_error_reporting) {
740 p = Place_report(place,errLevelText[ed->ed_level],0,message);
741 va_start(ap,ecode);
742 p += formatErrorMsg(p,ed,ap);
743 va_end(ap);
744 doErrorOutput(ed,message);
745 } else {
746 if (ed->ed_level > 0)
747 errCount++;
748 else
749 warnCount++;
750 }
751 #endif
752 }
753
754 /*****************************************************************************
755 *
756 * Generate a module error
757 *
758 * Parameters:
759 * m Module in which error occured.
760 * place Place identifier for location of the error.
761 * ecode Error code value
762 * ... Error-specific arguments
763 *
764 *****************************************************************************/
errorModule(ModuleDecl * m,Place * place,errorcode_t ecode,...)765 void errorModule(ModuleDecl *m,Place *place,errorcode_t ecode,...)
766 {
767 ErrorDescriptor *ed = findError(ecode);
768 char buf[STRMAX],*p;
769 va_list ap;
770
771 if (m->m_errorsDone) return;
772
773 p = Place_report(place,errLevelText[ed->ed_level],0,buf);
774
775 va_start(ap,ecode);
776 p += formatErrorMsg(p,ed,ap);
777 va_end(ap);
778
779 doErrorOutput(ed,buf);
780 }
781
782 /*****************************************************************************
783 *
784 * Generate a net error
785 *
786 * Parameters:
787 * m Module in which error occured.
788 * place Place identifier for location of the error.
789 * ecode Error code value
790 * ... Error-specific arguments
791 *
792 *****************************************************************************/
errorNet(ModuleDecl * m,const char * net,Place * place,errorcode_t ecode,...)793 void errorNet(ModuleDecl *m,const char *net,Place *place,errorcode_t ecode,...)
794 {
795 ErrorDescriptor *ed = findError(ecode);
796 char buf[STRMAX],*p;
797 va_list ap;
798
799 if (m->m_errorsDone) return;
800
801 p = Place_report(place,errLevelText[ed->ed_level],net,buf);
802
803 va_start(ap,ecode);
804 p += formatErrorMsg(p,ed,ap);
805 va_end(ap);
806
807 doErrorOutput(ed,buf);
808 }
809