/[ascend]/trunk/ascend/compiler/ascParse.y
ViewVC logotype

Contents of /trunk/ascend/compiler/ascParse.y

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2353 - (show annotations) (download)
Sat Jan 8 11:21:09 2011 UTC (11 years, 5 months ago) by jpye
File size: 70313 byte(s)
fixed bug in destruction of importhandler_library. More work still to be done there.
Improved parser message for failed IMPORT.
1 /*
2 ASCEND modelling environment
3
4 Copyright (C) 1990, 1993, 1994 Thomas Guthrie Epperly
5 Copyright (C) 1997 Benjamin Andrew Allan & Vicente Rico-Ramirez
6 Copyright (C) 1998, 2006 Carnegie Mellon University
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
11 any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330,
21 Boston, MA 02111-1307, USA.
22 *//*
23 ASCEND parser
24 by Tom Epperly
25 Last in CVS: $Revision: 1.23 $ $Date: 2000/01/25 02:25:59 $ $Author: ballan $
26 */
27
28 /*------------------------------------------------------------------------------
29 PROLOGUE
30 */
31 %{
32 #include <stdio.h>
33 #include <stdarg.h>
34 #include <limits.h> /* need DBL_MAX and LONG_MAX */
35 #include <float.h> /* on a NeXT they are in here */
36
37 #include <ascend/compiler/parser.h>
38
39 #include <ascend/general/ascMalloc.h>
40 #include <ascend/general/list.h>
41 #include <ascend/general/dstring.h>
42 #include <ascend/compiler/compiler.h>
43 #include <ascend/compiler/scanner.h>
44 #include <ascend/compiler/symtab.h> /* the global string/symbol table */
45 #include <ascend/compiler/notate.h> /* notes database wrapper */
46 #include <ascend/compiler/braced.h>
47 #include <ascend/compiler/fractions.h>
48 #include <ascend/compiler/dimen.h>
49 #include <ascend/compiler/functype.h>
50 #include <ascend/compiler/func.h>
51 #include <ascend/compiler/expr_types.h>
52 #include <ascend/compiler/name.h>
53 #include <ascend/compiler/nameio.h>
54 #include <ascend/compiler/instance_enum.h>
55 #include <ascend/compiler/extfunc.h>
56 #include <ascend/compiler/packages.h>
57 #include <ascend/compiler/sets.h>
58 #include <ascend/compiler/exprs.h>
59 #include <ascend/compiler/exprio.h>
60 #include <ascend/compiler/vlist.h>
61 #include <ascend/compiler/vlistio.h> /* for debugging only */
62 #include <ascend/compiler/stattypes.h>
63 #include <ascend/compiler/slist.h>
64 #include <ascend/compiler/statement.h>
65 #include <ascend/compiler/statio.h>
66 #include <ascend/compiler/units.h>
67 #include <ascend/compiler/when.h>
68 #include <ascend/compiler/select.h>
69 #include <ascend/compiler/switch.h>
70 #include <ascend/compiler/proc.h>
71 #include <ascend/compiler/watchpt.h>
72 #include <ascend/compiler/module.h>
73 #include <ascend/compiler/child.h>
74 #include <ascend/compiler/type_desc.h>
75 #include <ascend/compiler/type_descio.h>
76 #include <ascend/compiler/typedef.h>
77 #include <ascend/compiler/library.h>
78 #include <ascend/compiler/syntax.h>
79 #include <ascend/compiler/lexer.h>
80
81 /* 1 ==> expr can find missing , w/o shift/reduce conflicts */
82 #define COMMAEXPR_NOTBUGGY 0
83 #if COMMAEXPR_NOTBUGGY
84 #include <ascend/compiler/exprio.h>
85 #endif /* for CommaExpr if working. */
86
87 int g_compiler_warnings = 1; /* level of whine to allow */
88
89 #include <ascend/compiler/redirectFile.h>
90 #ifndef ASCERR
91 # error "ASCERR not defined"
92 #endif
93
94 extern int zz_error(char *);
95 /* provided at the end of this file.
96 * it increments g_untrapped_error, the global defined below
97 */
98
99 static unsigned long g_header_linenum = 0;
100 static unsigned int g_untrapped_error = 0;
101 /* if g_untrapped_error is set to 1, the current definition
102 * should be abandoned even if nothing else detectable by
103 * typedef.c exists. basically any syntax error should cause a type
104 * to be abandoned, but not all cause the parser to barf.
105 */
106
107 /* the last seen method name while processing a method */
108 static symchar *g_proc_name=NULL;
109
110 /* the last seen ATOM/MODEL/constant type and refinement base */
111 static symchar *g_type_name=NULL;
112 static symchar *g_refines_name=NULL;
113 /*
114 * g_type_name is used by the scanner when closing a module to check if
115 * the parser is in the middle of parsing a MODEL or ATOM type
116 * definition.
117 * g_type_name == NULL implies that the parser is in between
118 * definitions. This depends on proper
119 * resets to NULL at END of type productions.
120 * g_type_name != NULL implies that the parser is in the middle
121 * of a type definition and gives the name
122 * of that type.
123 */
124
125 static symchar *g_end_identifier = NULL;
126 /* This variable gets reset every time we see an ``END_TOK''. If the
127 * token after END_TOK is missing (i.e., ``END;'') or if it is recognized
128 * (e.g., FOR_TOK), set this variable to NULL. When we see an
129 * ``END_TOK IDENTIFIER_TOK'', set this variable to the pointer into the
130 * symbol table returned by the scanner.
131 */
132
133 static struct StatementList *g_model_parameters=NULL;
134 /* this is the statementlist of the parameterized type
135 */
136
137 static struct StatementList *g_parameter_wheres=NULL;
138 /* this is the where list of a parameterized type. restrictions on args
139 */
140
141 static struct StatementList *g_parameter_reduction=NULL;
142 /* this is the statementlist of the REFINES clause
143 * at present both might be null, which is bad.
144 */
145
146 static struct Set *g_typeargs=NULL;
147 /* optional args to a typename in part declaration.
148 * it is set in the production type_identifier. in
149 * contexts where args are not allowed, use IDENTIFIER_TOK instead of the
150 * type_identifier production.
151 */
152
153 static struct Set *g_callargs=NULL;
154 /* optional args to a user defined method.
155 * it is set in the production call_identifier. in
156 * contexts where args are not allowed, use IDENTIFIER_TOK instead of the
157 * type_identifier production.
158 */
159
160 static struct gl_list_t *g_notelist = NULL;
161 /*
162 * Notes accumulator until a type commits or destroys it.
163 */
164
165 static int g_defaulted; /* used for atoms,constants */
166
167 static CONST dim_type *g_dim_ptr; /* dim of last units parsed, or so */
168 static CONST dim_type *g_atom_dim_ptr; /* dim of DIMENSION decl */
169 static CONST dim_type *g_default_dim_ptr; /* dim of default value parsed */
170
171 static double g_default_double;
172 static long g_default_long;
173 symchar *g_default_symbol;
174 #define DOUBLECONSTANT 0
175 #define LONGCONSTANT 1
176 #define BOOLEANCONSTANT 2
177 #define SYMBOLCONSTANT 3
178 static int g_constant_type = DOUBLECONSTANT;
179 static CONST struct Units *g_units_ptr;
180
181 int g_parse_relns = 1;
182 /* Should we parse relations?
183 * 0 indicates don't parse relations
184 * 1 indicates process them
185 */
186
187 /* Forward declaration of error message reporting
188 * functions provided at the end of this file.
189 */
190 static void ErrMsg_Generic(CONST char *);
191 static void ErrMsg_CommaName(CONST char *, struct Name *);
192 #if COMMAEXPR_NOTBUGGY
193 static void ErrMsg_CommaExpr(CONST char *, struct Expr *);
194 #endif /* COMMAEXPR_NOTBUGGY */
195 static void ErrMsg_NullDefPointer(CONST char *);
196 static void ErrMsg_ParensBrackets(CONST char *);
197 static void WarnMsg_MismatchEnd(CONST char *, CONST char *,
198 unsigned long, CONST char *);
199 static CONST char *TokenAsString(unsigned long);
200
201 static void error_reporter_current_line(const error_severity_t sev, const char *fmt,...);
202
203 /** @page ascend-notes About 'NOTES' in ASCEND
204 *
205 * The parser will now parse a NOTES block as well as in-lined NOTES. As
206 * a matter of fact, the parser would probably parse FORTRAN now since it
207 * is very lenient. For the in-lined NOTES, I accept any "doubly-quoted"
208 * string after an `fname'. I am currently dropping the NOTE on the
209 * floor. Ideally, we should only accept an inline NOTE when we are
210 * creating a new thing, like in an IS_A statement or a labeled relation.
211 * That means either adding the optional_note to fname and whining at the
212 * user when he/she uses the in-lined notes incorrectly, or coming up
213 * with a fvarnotelist and fnamenote that accepts fnames and
214 * optional_notes in a list or a stand-alone form.
215 *
216 * For the block NOTES statement, the symtax is
217 *
218 * NOTES ( SYMBOL_TOK ( fvarlist BRACEDTEXT_TOK )+ )+ END NOTES ';'
219 *
220 * Here I am using () as part of the meta-language to describe the syntax
221 * to you, they are not part of the formal grammer. An example is
222 *
223 * NOTES
224 * 'text' a,b,c { Here is some text }
225 * d { Here is more text }
226 * 'html' SELF { <bold>html sucks</bold> }
227 * END NOTES;
228 *
229 * Note that the only punctuation is the `,' between the members of the
230 * fvarlist and the closing `;'. Right now, the term `SELF' would be
231 * eaten in the fvarlist production. I'm not sure if this is what we
232 * should do (which requires having the notes processing do something
233 * special when it sees SELF in the fvarlist), or if we should create
234 * a SELF_TOK token. The latter is certainly easier to implement from
235 * the parser's perspective, which is why I did it that way.
236 *
237 * The block NOTES statement doesn't do anything with its stuff either,
238 * the symbols and {bracedText} get dropped on the floor and I destroy
239 * the fvarlist, but that all that happens.
240 *
241 * The `notes_body' and `noteslist' productions return `notes_ptr', which
242 * right now is a `void*' until we can decide what type of data structure
243 * we want to handle NOTES.
244 *
245 * As an amusing side note, the parser will currently eat the following:
246 *
247 * NOTES
248 * 'fun' name "put some text here" {put more text here}
249 * END NOTES;
250 *
251 * Like I said, this is so the parser will eat them; it's not being real
252 * smart about what it does with them.
253 *
254 * For debugging the NOTES stuff, set the DEBUG_NOTES macro to the
255 * following:
256 *
257 * #define DEBUG_NOTES(s) FPRINTF(stderr,"****DISCARDED NOTES:\n%s****\n",(s))
258 *
259 * To completely ignore the NOTES, set DEBUG_NOTES to the following:
260 *
261 * #define DEBUG_NOTES(s) 0
262 *
263 * Note that if you do the latter, you'll get `statement with no effect'
264 * warnings from gcc -Wall.
265 *
266 * -- Mark Thomas Thursday, 13 March 1997
267 */
268 /* #define DEBUG_NOTES(s) 0 */
269 #define DEBUG_NOTES(s) ERROR_REPORTER_NOLINE(ASC_USER_WARNING,"Discarded note: %s", (s))
270
271 /*
272 * Because the ascend types and notes are not tightly bound to each other,
273 * what with notes being stored in a database,
274 * We collect notes locally until the type associated with a batch of notes
275 * is approved by typedef and other error checks. Then we process the
276 * collected notes, commiting them to the database.
277 *
278 * NOTES made via ADD NOTES do not require a type check first and the
279 * type may not even exist yet in the library.
280 *
281 * ProcessNotes(keep); Clear up collected list, commit them if keep != 0.
282 * CollectNote(note); Add a note to the collected list.
283 */
284 static void ProcessNotes(int);
285 static void CollectNote(struct Note *);
286
287 /* For 'inline' notes, note on DQUOTE_TOK from scanner.l:
288 * Remember that DQUOTE_TOK is a string value which is local to the
289 * production that finds it. It must be copied if you want to
290 * keep it.
291 */
292
293 /* MS VC++ won't compiler Bison output unless we switch this */
294 #ifdef _MSC_VER
295 # define __STDC__
296 #endif
297
298 %}
299 /* END OF PROLOGUE
300 ------------------------------------------------------------------------------
301 DEFINITION OF PARSER RETURN TYPE
302 */
303
304 %union {
305 double real_value;
306 long int_value;
307 struct fraction frac_value;
308 symchar *id_ptr;
309 CONST char *braced_ptr; /* pointer for units, explanations, tables */
310 symchar *sym_ptr; /* pointer for symbols */
311 CONST char *dquote_ptr; /* for text in "double quotes" */
312 struct Name *nptr;
313 struct Expr *eptr;
314 struct Set *sptr;
315 struct VariableList *lptr;
316 struct Statement *statptr;
317 struct StatementList *slptr;
318 struct SelectList *septr;
319 struct SwitchList *swptr;
320 struct WhenList *wptr;
321 struct NoteTmp *notesptr; /* change this once struct Notes is defined */
322 struct gl_list_t *listp;
323 struct InitProcedure *procptr;
324 CONST dim_type *dimp;
325 struct TypeDescription *tptr;
326 struct UnitDefinition *udefptr;
327 dim_type dimen;
328 enum ForOrder order;
329 enum ForKind fkind;
330 }
331
332 /*------------------------------------------------------------------------------
333 YACC TOKENS
334 */
335
336 %token ADD_TOK ALIASES_TOK AND_TOK ANY_TOK AREALIKE_TOK ARETHESAME_TOK ARRAY_TOK ASSERT_TOK ATOM_TOK
337 %token BEQ_TOK BNE_TOK BREAK_TOK
338 %token CALL_TOK CARD_TOK CASE_TOK CHOICE_TOK CHECK_TOK CONDITIONAL_TOK CONSTANT_TOK
339 %token CONTINUE_TOK CREATE_TOK
340 %token DATA_TOK DECREASING_TOK DEFAULT_TOK DEFINITION_TOK DIMENSION_TOK
341 %token DIMENSIONLESS_TOK DO_TOK
342 %token ELSE_TOK END_TOK EXPECT_TOK EXTERNAL_TOK
343 %token FALSE_TOK FALLTHRU_TOK FIX_TOK FOR_TOK FREE_TOK FROM_TOK
344 %token GLOBAL_TOK
345 %token IF_TOK IMPORT_TOK IN_TOK INPUT_TOK INCREASING_TOK INTERACTIVE_TOK
346 %token INTERSECTION_TOK ISA_TOK _IS_T ISREFINEDTO_TOK
347 %token MAXIMIZE_TOK MAXINTEGER_TOK MAXREAL_TOK METHODS_TOK METHOD_TOK MINIMIZE_TOK MODEL_TOK
348 %token NOT_TOK NOTES_TOK
349 %token OF_TOK OPTION_TOK OR_TOK OTHERWISE_TOK OUTPUT_TOK
350 %token PATCH_TOK PROD_TOK PROVIDE_TOK
351 %token REFINES_TOK REPLACE_TOK REQUIRE_TOK RETURN_TOK RUN_TOK
352 %token SATISFIED_TOK SELECT_TOK SIZE_TOK SOLVE_TOK SOLVER_TOK STOP_TOK SUCHTHAT_TOK SUM_TOK SWITCH_TOK
353 %token THEN_TOK TRUE_TOK
354 %token UNION_TOK UNITS_TOK UNIVERSAL_TOK
355 %token WHEN_TOK WHERE_TOK WHILE_TOK WILLBE_TOK WILLBETHESAME_TOK WILLNOTBETHESAME_TOK
356 %token ASSIGN_TOK CASSIGN_TOK DBLCOLON_TOK USE_TOK LEQ_TOK GEQ_TOK NEQ_TOK
357 %token DOTDOT_TOK WITH_TOK VALUE_TOK WITH_VALUE_T
358 %token <real_value> REAL_TOK
359 %token <int_value> INTEGER_TOK
360 %token <id_ptr> IDENTIFIER_TOK
361 %token <braced_ptr> BRACEDTEXT_TOK
362 %token <sym_ptr> SYMBOL_TOK
363 %token <dquote_ptr> DQUOTE_TOK
364
365 /* Set associativities */
366 %left ',' '|' SUCHTHAT_TOK
367 %left BEQ_TOK BNE_TOK
368 %left AND_TOK OR_TOK IN_TOK
369 %left '<' '=' '>' LEQ_TOK GEQ_TOK NEQ_TOK
370 %left '+' '-'
371 %left '/' '*'
372 %left UMINUS_TOK UPLUS_TOK
373 %right '^'
374 %left NOT_TOK
375 %start definitions
376
377 %type <real_value> default_val number realnumber opunits
378 %type <int_value> end optional_sign universal
379 %type <fkind> forexprend
380 %type <frac_value> fraction fractail
381 %type <id_ptr> optional_of optional_method type_identifier call_identifier
382 %type <dquote_ptr> optional_notes
383 %type <braced_ptr> optional_bracedtext
384 %type <nptr> data_args fname name optional_scope
385 %type <eptr> relation expr relop logrelop optional_with_value
386 %type <sptr> set setexprlist optional_set_values
387 %type <lptr> fvarlist input_args output_args varlist
388
389 %type <statptr> statement isa_statement willbe_statement aliases_statement
390 %type <statptr> is_statement isrefinedto_statement arealike_statement
391 %type <statptr> arethesame_statement willbethesame_statement
392 %type <statptr> willnotbethesame_statement assignment_statement
393 %type <statptr> relation_statement glassbox_statement blackbox_statement
394 %type <statptr> call_statement units_statement
395 %type <statptr> external_statement for_statement run_statement if_statement assert_statement fix_statement free_statement
396 %type <statptr> when_statement use_statement select_statement
397 %type <statptr> conditional_statement notes_statement
398 %type <statptr> flow_statement while_statement
399 %type <statptr> solve_statement solver_statement option_statement switch_statement
400
401 %type <slptr> fstatements global_def optional_else
402 %type <slptr> optional_model_parameters optional_parameter_reduction
403 %type <slptr> optional_parameter_wheres
404 %type <septr> selectlist selectlistf
405 %type <swptr> switchlist switchlistf
406 %type <wptr> whenlist whenlistf
407 %type <notesptr> notes_body noteslist
408 %type <listp> methods proclist proclistf statements unitdeflist
409 %type <procptr> procedure
410 %type <dimp> dims dimensions
411 %type <dimen> dimexpr
412 %type <order> optional_direction
413 %type <tptr> add_method_head replace_method_head
414 %type <udefptr> unitdef
415 %type <id_ptr> model_id atom_id procedure_id definition_id
416
417 /* stuff without a particular need for a type */
418
419 /*------------------------------------------------------------------------------
420 GRAMMAR RULES
421 */
422
423 %%
424
425 definitions:
426 /* empty */
427 | definitions definition
428 ;
429
430 definition:
431 require_file
432 | provide_module
433 | import
434 | add_method_def
435 | replace_method_def
436 | add_notes_def
437 | constant_def
438 | atom_def
439 | model_def
440 | definition_def
441 | patch_def
442 | units_def
443 | global_def
444 | error
445 {
446 ErrMsg_Generic("Error in definition.");
447 }
448 ;
449
450 global_def:
451 GLOBAL_TOK ';' fstatements end ';'
452 {
453 /* the following steps apply to string buffers only, not files */
454 struct gl_list_t *stats;
455 int dispose;
456 if ($3 != NULL) {
457 stats = gl_create(1L);
458 gl_append_ptr(stats,(void *)$3);
459 if (g_untrapped_error) {
460 ErrMsg_Generic("Because of a syntax error, the following statements are being ignored:");
461 WriteStatementList(ASCERR,$3,4);
462 DestroyStatementList($3);
463 }else{
464 dispose = Asc_ModuleAddStatements(Asc_CurrentModule(),stats);
465 switch (dispose) {
466 case 1: /* appended */
467 if (stats != NULL) {
468 gl_destroy(stats);
469 }
470 break;
471 case 0: /* kept */
472 break;
473 case -1: /* illegal in file */
474 ErrMsg_Generic("GLOBAL statements can only be made interactively. Ignoring:");
475 if (stats != NULL) {
476 WriteStatementList(ASCERR,$3,4);
477 gl_iterate(stats,(DestroyFunc)DestroyStatementList);
478 gl_destroy(stats);
479 }
480 break;
481 default:
482 break;
483 }
484 }
485 }
486 /* don't let any bizarreness in string parsing hang around */
487 g_type_name = g_refines_name = g_proc_name = NULL;
488 g_model_parameters =
489 g_parameter_reduction =
490 g_parameter_wheres = NULL;
491 g_untrapped_error = 0;
492 }
493 ;
494
495 require_file:
496 REQUIRE_TOK DQUOTE_TOK ';'
497 {
498 Asc_ScannerPushBuffer($2);
499 }
500 | REQUIRE_TOK name ';'
501 {
502 DestroyName($2);
503 ErrMsg_Generic("REQUIRE statement syntax is 'REQUIRE \"filename\";'.");
504 }
505 | REQUIRE_TOK name
506 {
507 DestroyName($2);
508 ErrMsg_Generic("REQUIRE statement syntax is 'REQUIRE \"filename\";'.");
509 }
510 ;
511
512 provide_module:
513 PROVIDE_TOK DQUOTE_TOK ';'
514 {
515 Asc_ModuleCreateAlias(Asc_CurrentModule(),$2);
516 }
517 | PROVIDE_TOK name ';'
518 {
519 DestroyName($2);
520 ErrMsg_Generic("PROVIDE statement syntax is 'PROVIDE \"filename\";'.");
521 }
522 | PROVIDE_TOK name
523 {
524 DestroyName($2);
525 ErrMsg_Generic("PROVIDE statement syntax is 'PROVIDE \"filename\";'.");
526 }
527 ;
528
529 import:
530 IMPORT_TOK IDENTIFIER_TOK FROM_TOK DQUOTE_TOK ';'
531 {
532 if(package_load($4,SCP($2))){
533 error_reporter_current_line(ASC_USER_ERROR
534 ,"IMPORT of '%s' from '%s'."
535 ,SCP($4), SCP($2)
536 );
537 }
538 }
539 | IMPORT_TOK DQUOTE_TOK ';'
540 {
541 if(package_load(SCP($2),NULL)){
542 error_reporter_current_line(ASC_USER_ERROR
543 ,"IMPORT of '%s' failed."
544 ,SCP($2)
545 );
546 }
547 }
548 ;
549
550 add_notes_def:
551 add_notes_head notes_body end ';'
552 {
553 /* see comments for notes statement. */
554 if( $3 != NOTES_TOK ) {
555 WarnMsg_MismatchEnd("NOTES", NULL, $3, NULL);
556 }
557 if ($2 != NULL) {
558 struct NoteTmp *nt;
559 symchar *lang=NULL; /* dummy */
560 nt = $2;
561 while (nt != NULL) {
562 if (nt->lang != NULL) {
563 lang = nt->lang;
564 }
565 /* save exploding vardata to simple entries until we keep */
566 CollectNote(CreateNote(g_type_name, lang, NULL, g_proc_name,
567 Asc_ModuleBestName(Asc_CurrentModule()),
568 nt->bt,
569 nt->line, nt->vardata, nd_vlist));
570 nt = nt->next;
571 }
572 /* now keep them */
573 ProcessNotes(1);
574 DestroyNoteTmpList($2);
575 }
576 g_type_name = g_proc_name = NULL;
577 g_untrapped_error = 0;
578 }
579 ;
580
581 add_notes_head:
582 ADD_TOK NOTES_TOK IN_TOK IDENTIFIER_TOK optional_method ';'
583 {
584 g_type_name = $4;
585 g_proc_name = $5;
586 }
587 ;
588
589 add_method_def:
590 add_method_head proclist end ';'
591 {
592 if ($1 == NULL) {
593 DestroyProcedureList($2);
594 } else {
595 if( $3 != METHODS_TOK ) {
596 WarnMsg_MismatchEnd("ADD METHODS", NULL, $3, "METHODS");
597 }
598 if (AddMethods($1,$2,g_untrapped_error) != 0) {
599 if ($1 != ILLEGAL_DEFINITION) {
600 error_reporter_current_line(ASC_USER_ERROR
601 ,"ADD METHODS failed for type %s"
602 ,SCP(GetName($1))
603 );
604 DestroyProcedureList($2);
605 } /* else adding in DEFINITION MODEL may have misgone */
606 }
607 }
608 g_untrapped_error = 0;
609 }
610 ;
611
612 add_method_head:
613 ADD_TOK METHODS_TOK IN_TOK IDENTIFIER_TOK ';'
614 {
615 struct TypeDescription *tmptype;
616 tmptype = FindType($4);
617 if(tmptype == NULL){
618 error_reporter_current_line(ASC_USER_ERROR
619 ,"ADD METHODS called with undefined type (%s)"
620 ,SCP($4)
621 );
622 }
623 $$ = tmptype; /* parent should check for NULL */
624 g_type_name = $4; /* scope for notes */
625 }
626 | ADD_TOK METHODS_TOK IN_TOK DEFINITION_TOK MODEL_TOK ';'
627 {
628 $$ = ILLEGAL_DEFINITION;
629 /* need a bit of global state here to tag base methods */
630 }
631 ;
632
633 replace_method_def:
634 replace_method_head proclist end ';'
635 {
636 if ($1 == NULL) {
637 DestroyProcedureList($2);
638 } else {
639 if( $3 != METHODS_TOK ) {
640 WarnMsg_MismatchEnd("REPLACE METHODS", NULL, $3, "METHODS");
641 }
642 if (ReplaceMethods($1,$2,g_untrapped_error) != 0) {
643 error_reporter_current_line(ASC_USER_ERROR
644 ,"REPLACE METHODS failed for type %s"
645 ,SCP(GetName($1))
646 );
647 DestroyProcedureList($2);
648 }
649 }
650 g_untrapped_error = 0;
651 }
652 ;
653
654 replace_method_head:
655 REPLACE_TOK METHODS_TOK IN_TOK IDENTIFIER_TOK ';'
656 {
657 struct TypeDescription *tmptype;
658 tmptype = FindType($4);
659 if (tmptype == NULL) {
660 error_reporter_current_line(ASC_USER_ERROR
661 ,"REPLACE METHODS called with undefined type (%s)"
662 ,SCP($4)
663 );
664 }
665 $$ = tmptype; /* parent should check for NULL */
666 }
667 | REPLACE_TOK METHODS_TOK IN_TOK DEFINITION_TOK MODEL_TOK ';'
668 {
669 $$ = ILLEGAL_DEFINITION;
670 /* need a bit of global state here to tag base methods */
671 }
672 ;
673
674 atom_def:
675 universal atom_head fstatements methods end ';'
676 {
677 struct TypeDescription *def_ptr;
678 int keepnotes = 0;
679
680 if(( $5 != IDENTIFIER_TOK ) || ( g_end_identifier != g_type_name )) {
681 /* all identifier_t are from symbol table, so ptr match
682 * is sufficient for equality.
683 */
684 WarnMsg_MismatchEnd("ATOM", SCP(g_type_name),
685 $5, SCP(g_type_name));
686 }
687 g_atom_dim_ptr = CheckDimensionsMatch(g_default_dim_ptr,
688 g_atom_dim_ptr);
689 if (g_atom_dim_ptr != NULL) {
690 def_ptr = CreateAtomTypeDef(g_type_name,
691 g_refines_name,
692 real_type, /* ignored..really */
693 Asc_CurrentModule(),
694 $1,
695 $3,
696 $4,
697 g_defaulted,
698 g_default_double,
699 g_atom_dim_ptr,
700 g_default_long,
701 g_default_symbol,
702 g_untrapped_error);
703 if (def_ptr != NULL) {
704 keepnotes = AddType(def_ptr);
705 } else {
706 /* CreateAtomTypeDef is responsible for freeing (if needed)
707 * all args sent to it event of failure so we don't have to.
708 * In particular $3 $4 should be killed before returning NULL.
709 */
710 ErrMsg_NullDefPointer(SCP(g_type_name));
711 }
712 } else {
713 error_reporter(ASC_USER_ERROR,Asc_ModuleBestName(Asc_CurrentModule()),g_header_linenum,NULL
714 ,"Atom dimensions don't match in ATOM %s"
715 ,SCP(g_type_name)
716 );
717 DestroyStatementList($3);
718 DestroyProcedureList($4);
719 }
720 ProcessNotes(keepnotes);
721 g_type_name = g_refines_name = g_proc_name = NULL;
722 g_untrapped_error = 0;
723 }
724 ;
725
726 atom_head:
727 atom_id REFINES_TOK IDENTIFIER_TOK dims default_val ';'
728 {
729 /* g_type_name = $1; */
730 g_refines_name = $3;
731 g_atom_dim_ptr = $4;
732 g_default_double = $5;
733 g_header_linenum = LineNum();
734 }
735 ;
736
737 atom_id:
738 ATOM_TOK IDENTIFIER_TOK
739 {
740 $$ = $2;
741 g_type_name = $2; /* want this set early so parm lists see it */
742 }
743 ;
744
745 default_val:
746 /* empty */
747 {
748 $$ = 0.0;
749 g_default_dim_ptr = WildDimension();
750 g_defaulted = 0;
751 }
752 | DEFAULT_TOK optional_sign number
753 {
754 $$ = $2 ? -$3 : $3;
755 g_defaulted = 1;
756 }
757 | DEFAULT_TOK FALSE_TOK
758 {
759 $$ = 0.0;
760 g_default_dim_ptr = Dimensionless();
761 g_default_long = 0;
762 g_defaulted = 1;
763 }
764 | DEFAULT_TOK TRUE_TOK
765 {
766 $$ = 0.0;
767 g_default_dim_ptr = Dimensionless();
768 g_default_long = 1;
769 g_defaulted = 1;
770 }
771 | DEFAULT_TOK SYMBOL_TOK
772 {
773 $$ = 0.0;
774 g_default_dim_ptr = Dimensionless();
775 g_default_symbol = $2;
776 g_defaulted = 0;
777 }
778 ;
779
780 constant_def:
781 universal constant_head
782 {
783 struct TypeDescription *def_ptr;
784 int keepnotes = 0;
785 if (g_defaulted) {
786 g_atom_dim_ptr = CheckDimensionsMatch(g_default_dim_ptr,
787 g_atom_dim_ptr);
788 }
789 if (g_atom_dim_ptr != NULL) {
790 def_ptr = CreateConstantTypeDef(g_type_name,
791 g_refines_name,
792 Asc_CurrentModule(),
793 $1,
794 g_defaulted,
795 g_default_double,
796 g_default_long,
797 g_default_symbol,
798 g_atom_dim_ptr,
799 g_untrapped_error);
800 if (def_ptr != NULL) {
801 keepnotes = AddType(def_ptr);
802 } else {
803 ErrMsg_NullDefPointer(SCP(g_type_name));
804 }
805 } else {
806 error_reporter(ASC_USER_ERROR,Asc_ModuleBestName(Asc_CurrentModule()),g_header_linenum,NULL,
807 "Constant dimensions don't match in CONSTANT %s"
808 " on line %s:%lu.\n",
809 SCP(g_type_name),
810 Asc_ModuleBestName(Asc_CurrentModule()),
811 g_header_linenum);
812 }
813 ProcessNotes(keepnotes);
814 g_type_name = g_refines_name = NULL;
815 g_untrapped_error = 0;
816 }
817 ;
818
819 constant_head:
820 CONSTANT_TOK IDENTIFIER_TOK REFINES_TOK IDENTIFIER_TOK dims constant_val
821 optional_notes ';'
822 {
823 g_type_name = $2;
824 g_refines_name = $4;
825 g_atom_dim_ptr = $5;
826 switch (g_constant_type) {
827 case DOUBLECONSTANT:
828 g_default_double = $<real_value>6;
829 break;
830 case LONGCONSTANT:
831 g_default_long = $<real_value>6;
832 break;
833 case BOOLEANCONSTANT:
834 g_default_long = $<int_value>6;
835 break;
836 case SYMBOLCONSTANT:
837 g_default_symbol = $<sym_ptr>6;
838 break;
839 default:
840 ErrMsg_Generic("Wierd constant type assign encountered.");
841 break; /* better not be reached. */
842 }
843 g_header_linenum = LineNum();
844 if ($7 != NULL) {
845 CollectNote(CreateNote(g_type_name,InlineNote(),SelfNote(),NULL,
846 Asc_ModuleBestName(Asc_CurrentModule()),
847 AddBraceChar($7,InlineNote()),
848 g_header_linenum,NULL,nd_empty));
849 }
850 }
851 ;
852
853 constant_val:
854 /* empty */
855 {
856 $<real_value>$ = 0.0;
857 g_default_dim_ptr = WildDimension();
858 g_defaulted = 0;
859 }
860 | CASSIGN_TOK optional_sign number
861 {
862 $<real_value>$ = $2 ? -$3 : $3;
863 g_defaulted = 1;
864 }
865 | CASSIGN_TOK TRUE_TOK
866 {
867 $<int_value>$ = 1;
868 g_defaulted = 1;
869 g_default_dim_ptr = Dimensionless();
870 g_constant_type = BOOLEANCONSTANT;
871 }
872 | CASSIGN_TOK FALSE_TOK
873 {
874 $<int_value>$ = 0;
875 g_defaulted = 1;
876 g_default_dim_ptr = Dimensionless();
877 g_constant_type = BOOLEANCONSTANT;
878 }
879 | CASSIGN_TOK SYMBOL_TOK
880 {
881 $<sym_ptr>$ = $2;
882 g_defaulted = 1;
883 g_default_dim_ptr = Dimensionless();
884 g_constant_type = SYMBOLCONSTANT;
885 }
886 ;
887
888 model_def:
889 universal model_head fstatements methods end ';'
890 {
891 struct TypeDescription *def_ptr;
892 int keepnotes = 0;
893 if(( $5 != IDENTIFIER_TOK ) || ( g_end_identifier != g_type_name )) {
894 /* all identifier_t are from symbol table, so ptr match
895 * is sufficient for equality.
896 */
897 WarnMsg_MismatchEnd("MODEL", SCP(g_type_name),
898 $5, SCP(g_type_name));
899 }
900 def_ptr = CreateModelTypeDef(g_type_name,
901 g_refines_name,
902 Asc_CurrentModule(),
903 $1,
904 $3,
905 $4,
906 g_model_parameters,
907 g_parameter_reduction,
908 g_parameter_wheres,
909 g_untrapped_error);
910 if (def_ptr != NULL) {
911 keepnotes = AddType(def_ptr);
912 } else {
913 /* CreateModelTypeDef is responsible for freeing (if needed)
914 * all args sent to it so we don't have to here.
915 * in particular $3 $4 g_model_parameters, g_parameter_reduction,
916 * and g_parameter_wheres.
917 */
918 ErrMsg_NullDefPointer(SCP(g_type_name));
919 }
920 ProcessNotes(keepnotes);
921 g_type_name = g_refines_name = NULL;
922 g_model_parameters =
923 g_parameter_reduction =
924 g_parameter_wheres = NULL;
925 g_untrapped_error = 0;
926 }
927 ;
928
929 model_head:
930 model_id optional_model_parameters
931 optional_parameter_wheres ';'
932 {
933 /* g_type_name = $1; */
934 g_model_parameters = $2;
935 g_parameter_wheres = $3;
936 g_refines_name = NULL;
937 g_header_linenum = LineNum();
938 }
939 | model_id optional_model_parameters optional_parameter_wheres
940 REFINES_TOK IDENTIFIER_TOK optional_parameter_reduction ';'
941 {
942 /* g_type_name = $1; */
943 g_model_parameters = $2;
944 g_parameter_wheres = $3;
945 g_refines_name = $5;
946 g_parameter_reduction = $6;
947 g_header_linenum = LineNum();
948 }
949 ;
950
951 model_id:
952 MODEL_TOK IDENTIFIER_TOK
953 {
954 $$ = $2;
955 g_type_name = $2; /* want this set early so parm lists see it */
956 }
957 ;
958
959 optional_model_parameters:
960 /* empty */
961 {
962 $$ = NULL;
963 }
964 | '(' fstatements ')'
965 {
966 $$ = $2; /* this could be much more sophisticated */
967 }
968 ;
969
970 optional_parameter_wheres:
971 /* empty */
972 {
973 $$ = NULL;
974 }
975 | WHERE_TOK '(' fstatements ')'
976 {
977 $$ = $3; /* this could be much more sophisticated */
978 }
979 ;
980
981 optional_parameter_reduction:
982 /* empty */
983 {
984 $$ = NULL;
985 }
986 | '(' fstatements ')'
987 {
988 $$ = $2; /* this could be much more sophisticated */
989 }
990 ;
991
992 patch_def:
993 patch_head fstatements methods end ';'
994 {
995 struct TypeDescription *def_ptr;
996 if (($4 != IDENTIFIER_TOK ) || ( g_end_identifier != g_type_name )) {
997 /* all identifier_t are from symbol table, so ptr match
998 * is sufficient for equality.
999 */
1000 WarnMsg_MismatchEnd("PATCH", SCP(g_type_name),
1001 $4, SCP(g_type_name));
1002 }
1003 def_ptr = CreatePatchTypeDef(g_type_name,
1004 g_refines_name,
1005 NULL,
1006 Asc_CurrentModule(),
1007 $2,
1008 $3,
1009 g_untrapped_error);
1010 g_untrapped_error = 0;
1011 if (def_ptr != NULL) {
1012 AddType(def_ptr);
1013 } else {
1014 /* CreatePatchTypeDef is responsible for freeing (if needed)
1015 * all args sent to it so we don't have to here.
1016 * in particular $2 $3
1017 */
1018 ErrMsg_NullDefPointer(SCP(g_type_name));
1019 }
1020 g_type_name = g_refines_name = g_proc_name = NULL;
1021 }
1022 ;
1023
1024 patch_head:
1025 PATCH_TOK IDENTIFIER_TOK FOR_TOK IDENTIFIER_TOK ';'
1026 {
1027 /*
1028 * A patch definition looks just like a model def.
1029 * with the original name <=> refine name.
1030 */
1031 g_type_name = $2;
1032 g_refines_name = $4;
1033 g_header_linenum = LineNum();
1034 }
1035 ;
1036
1037 universal:
1038 /* empty */
1039 {
1040 $$ = 0;
1041 }
1042 | UNIVERSAL_TOK
1043 {
1044 $$ = 1;
1045 }
1046 ;
1047
1048 definition_def:
1049 definition_id fstatements methods end ';'
1050 {
1051 struct TypeDescription *def_ptr;
1052 int keepnotes = 0;
1053
1054 if(( $4 != IDENTIFIER_TOK ) || ( g_end_identifier != $1 )) {
1055 WarnMsg_MismatchEnd("DEFINITION", SCP($1), $4, SCP($1));
1056 }
1057 if( $1 == GetBaseTypeName(relation_type)) {
1058 def_ptr = CreateRelationTypeDef(Asc_CurrentModule(),$1,$2,$3);
1059 }
1060 else if( $1 == GetBaseTypeName(logrel_type) ) {
1061 def_ptr = CreateLogRelTypeDef(Asc_CurrentModule(),$1,$2,$3);
1062 }
1063 else {
1064 ErrMsg_Generic("Bad type passed to DEFINITION statement.");
1065 def_ptr = NULL;
1066 }
1067 if ( def_ptr != NULL ) {
1068 keepnotes = AddType(def_ptr);
1069 } else {
1070 ErrMsg_NullDefPointer(SCP($1));
1071 }
1072 ProcessNotes(keepnotes);
1073 g_type_name = NULL;
1074 g_untrapped_error = 0;
1075 }
1076 ;
1077
1078 definition_id:
1079 DEFINITION_TOK IDENTIFIER_TOK
1080 {
1081 $$ = $2;
1082 g_type_name = $2; /* want this set early so parm lists see it */
1083 }
1084 ;
1085
1086
1087 units_def:
1088 units_statement ';'
1089 { /* nothing to do. just cruft to fix ; problem */ }
1090 ;
1091
1092 units_statement:
1093 UNITS_TOK unitdeflist end
1094 {
1095 struct UnitDefinition *ud;
1096 unsigned long c,len;
1097
1098 if( $3 != UNITS_TOK ) {
1099 WarnMsg_MismatchEnd("UNITS", NULL, $3, NULL);
1100 }
1101 len = gl_length($2);
1102 for (c=1; c <= len; c++) {
1103 ud = (struct UnitDefinition *)gl_fetch($2,c);
1104 ProcessUnitDef(ud);
1105 DestroyUnitDef(ud);
1106 }
1107 gl_destroy($2);
1108 $$ = NULL;
1109 }
1110 ;
1111
1112 unitdeflist:
1113 {
1114 $$ = gl_create(100L);
1115 }
1116 | unitdeflist unitdef
1117 {
1118 gl_append_ptr($1,(char *)$2);
1119 $$ = $1;
1120 }
1121 ;
1122
1123 unitdef:
1124 IDENTIFIER_TOK '=' BRACEDTEXT_TOK ';'
1125 {
1126 $$ = CreateUnitDef($1,$3,Asc_ModuleBestName(Asc_CurrentModule()),
1127 LineNum());
1128 }
1129 ;
1130
1131
1132 methods:
1133 /* empty */
1134 {
1135 $$ = NULL;
1136 }
1137 | METHODS_TOK
1138 { /* To get rid of this, we will need a global proclist
1139 * that accumulates procs until a MODEL production is
1140 * completed. If any other sort of production is started,
1141 * and proclist is not NULL, it should be discarded.
1142 */
1143 }
1144 proclist
1145 {
1146 $$ = $3;
1147 }
1148 ;
1149
1150 proclist:
1151 proclistf
1152 {
1153 $$ = $1;
1154 gl_sort($$,(CmpFunc)CmpProcs);
1155 }
1156 ;
1157
1158 proclistf:
1159 {
1160 $$ = gl_create(7L);
1161 }
1162 | proclistf procedure
1163 {
1164 unsigned long c;
1165 struct InitProcedure *oldproc;
1166 c = gl_length($1);
1167 while (c > 0) {
1168 oldproc = (struct InitProcedure *)gl_fetch($1,c);
1169 if (ProcName($2) == ProcName(oldproc)) {
1170 error_reporter_current_line(ASC_USER_WARNING
1171 ,"Duplicate METHOD %s rejected", SCP(ProcName($2))
1172 );
1173 break;
1174 }
1175 c--;
1176 }
1177 if (c) { /* broke early */
1178 DestroyProcedure($2);
1179 } else {
1180 gl_append_ptr($1,(char *)$2);
1181 }
1182 $$ = $1;
1183 }
1184 ;
1185
1186 procedure:
1187 procedure_id ';' fstatements end ';'
1188 {
1189 if (($4 != IDENTIFIER_TOK) || ($1 != g_end_identifier)) {
1190 /* all identifier_t are from symbol table, so ptr match
1191 * is sufficient for equality.
1192 */
1193 WarnMsg_MismatchEnd("METHOD", SCP($1), $4, SCP($1));
1194 }
1195 $$ = CreateProcedure($1,$3);
1196 g_proc_name = NULL;
1197 }
1198 ;
1199
1200 procedure_id:
1201 METHOD_TOK IDENTIFIER_TOK
1202 {
1203 $$ = $2;
1204 g_proc_name = $2;
1205 }
1206 ;
1207
1208
1209 fstatements:
1210 statements
1211 {
1212 $$ = CreateStatementList($1);
1213 }
1214 ;
1215
1216 statements:
1217 /* empty */
1218 {
1219 $$ = gl_create(7L);
1220 }
1221 | statements statement ';'
1222 {
1223 /* this is appending to a gllist of statements, not yet slist. */
1224 if ($2 != NULL) {
1225 gl_append_ptr($1,(char *)$2);
1226 }
1227 $$ = $1;
1228 }
1229 | statements error ';'
1230 {
1231 ErrMsg_Generic("Error in statement input.");
1232 $$ = $1;
1233 }
1234 ;
1235
1236 statement:
1237 isa_statement
1238 | willbe_statement
1239 | aliases_statement
1240 | is_statement
1241 | isrefinedto_statement
1242 | arealike_statement
1243 | arethesame_statement
1244 | willbethesame_statement
1245 | willnotbethesame_statement
1246 | assignment_statement
1247 | relation_statement
1248 | glassbox_statement
1249 | blackbox_statement
1250 | call_statement
1251 | external_statement
1252 | for_statement
1253 | run_statement
1254 | fix_statement
1255 | free_statement
1256 | solver_statement
1257 | solve_statement
1258 | option_statement
1259 | assert_statement
1260 | if_statement
1261 | while_statement
1262 | when_statement
1263 | use_statement
1264 | flow_statement
1265 | select_statement
1266 | switch_statement
1267 | conditional_statement
1268 | notes_statement
1269 | units_statement
1270 ;
1271
1272 isa_statement:
1273 fvarlist ISA_TOK type_identifier optional_of optional_with_value
1274 {
1275 struct TypeDescription *tmptype;
1276 tmptype = FindType($3);
1277 if ($5 != NULL) {
1278 ErrMsg_Generic("WITH VALUE clause not allowed in IS_A.");
1279 g_untrapped_error++;
1280 DestroyVariableList($1);
1281 DestroySetList(g_typeargs);
1282 DestroyExprList($5);
1283 $$ = NULL;
1284 } else {
1285 if (tmptype != NULL) {
1286 if ((GetBaseType(tmptype) != model_type) &&
1287 (g_typeargs != NULL)) {
1288 error_reporter_current_line(ASC_USER_ERROR,
1289 "IS_A has arguments to the nonmodel type %s.\n",
1290 SCP($3));
1291 DestroyVariableList($1);
1292 DestroySetList(g_typeargs);
1293 DestroyExprList($5);
1294 g_untrapped_error++;
1295 $$ = NULL;
1296 } else {
1297 $$ = CreateISA($1,$3,g_typeargs,$4);
1298 }
1299 } else {
1300 error_reporter_current_line(ASC_USER_ERROR,"IS_A uses the undefined type %s.", SCP($3));
1301 DestroyVariableList($1);
1302 DestroySetList(g_typeargs);
1303 DestroyExprList($5);
1304 g_untrapped_error++;
1305 $$ = NULL;
1306 }
1307 }
1308 g_typeargs = NULL;
1309
1310 }
1311 ;
1312
1313 willbe_statement:
1314 fvarlist WILLBE_TOK type_identifier optional_of optional_with_value
1315 {
1316 struct TypeDescription *tmptype;
1317 tmptype = FindType($3);
1318 if (tmptype != NULL) {
1319 if ((GetBaseType(tmptype) != model_type) &&
1320 (g_typeargs != NULL)) {
1321 error_reporter_current_line(ASC_USER_ERROR,"WILL_BE has arguments to the nonmodel type '%s'",SCP($3));
1322 DestroyVariableList($1);
1323 DestroySetList(g_typeargs);
1324 DestroyExprList($5);
1325 g_untrapped_error++;
1326 $$ = NULL;
1327 } else {
1328 $$ = CreateWILLBE($1,$3,g_typeargs,$4,$5);
1329 }
1330 } else {
1331 DestroyVariableList($1);
1332 DestroySetList(g_typeargs);
1333 DestroyExprList($5);
1334 g_untrapped_error++;
1335 $$ = NULL;
1336 error_reporter_current_line(ASC_USER_ERROR,"WILL_BE uses the undefined type %s.",SCP($3));
1337 }
1338 g_typeargs = NULL;
1339 }
1340 ;
1341
1342 aliases_statement:
1343 fvarlist ALIASES_TOK fname
1344 {
1345 $$ = CreateALIASES($1,$3);
1346 }
1347 | fvarlist ALIASES_TOK '(' fvarlist ')' WHERE_TOK fvarlist ISA_TOK
1348 IDENTIFIER_TOK OF_TOK IDENTIFIER_TOK optional_set_values
1349 {
1350 int carray_err;
1351 carray_err = 0;
1352 if (VariableListLength($1) != 1L) {
1353 carray_err = 1;
1354 error_reporter_current_line(ASC_USER_ERROR,
1355 "Compound ALIASES allows only 1 LHS name. Found:");
1356 WriteVariableList(ASCERR,$1);
1357 }
1358 if (VariableListLength($7) != 1L) {
1359 carray_err = 1;
1360 error_reporter_current_line(ASC_USER_ERROR,
1361 "Compound ALIASES/IS_A allows only one LHS name. Found:");
1362 WriteVariableList(ASCERR,$7);
1363 }
1364 /* verify $9 == "set" */
1365 if (!carray_err && $9 != GetBaseTypeName(set_type)) {
1366 carray_err = 1;
1367 error_reporter_current_line(ASC_USER_ERROR,"Compound ALIASES statement requires IS_A %s. ",SCP(GetBaseTypeName(set_type)));
1368 FPRINTF(ASCERR," Found %s.\n",SCP($9));
1369 }
1370 /* verify set type */
1371 if ((!carray_err) &&
1372 ($11 != GetBaseTypeName(symbol_constant_type)) &&
1373 ($11 != GetBaseTypeName(integer_constant_type))) {
1374 carray_err = 1;
1375 error_reporter_current_line(ASC_USER_ERROR,
1376 "Compound ALIASES IS_A statement requires %s or %s.\n",
1377 SCP(GetBaseTypeName(integer_constant_type)),
1378 SCP(GetBaseTypeName(symbol_constant_type)));
1379 FPRINTF(ASCERR," Found %s.\n",SCP($11));
1380 }
1381 if (carray_err) {
1382 DestroyVariableList($1);
1383 DestroyVariableList($4);
1384 DestroyVariableList($7);
1385 DestroySetList($12);
1386 g_untrapped_error++;
1387 $$ = NULL;
1388 } else {
1389 int intset;
1390 intset = ($11 == GetBaseTypeName(integer_constant_type));
1391 $$ = CreateARR($1,$4,$7,intset,$12);
1392 }
1393 }
1394 ;
1395
1396 optional_set_values:
1397 /* empty */
1398 {
1399 $$ = NULL;
1400 }
1401 | WITH_VALUE_T '(' set ')'
1402 {
1403 $$ = $3;
1404 }
1405 ;
1406
1407 is_statement:
1408 fvarlist _IS_T IDENTIFIER_TOK optional_of
1409 {
1410 if (FindType($3)) {
1411 $$ = CreateREF($1,$3,$4,1);
1412 } else {
1413 $$ = CreateREF($1,$3,$4,1);
1414 error_reporter_current_line(ASC_USER_WARNING,"_IS_ uses the unbuilt prototype %s.\n",SCP($3));
1415 }
1416 }
1417 ;
1418
1419 isrefinedto_statement:
1420 fvarlist ISREFINEDTO_TOK type_identifier
1421 {
1422 struct TypeDescription *tmptype;
1423 tmptype = FindType($3);
1424 if (tmptype != NULL) {
1425 if ((GetBaseType(tmptype) != model_type) &&
1426 (g_typeargs != NULL)) {
1427 error_reporter_current_line(ASC_USER_ERROR,"IS_REFINED_TO has arguments to the nonmodel type %s.",SCP($3));
1428 DestroyVariableList($1);
1429 DestroySetList(g_typeargs);
1430 g_untrapped_error++;
1431 $$ = NULL;
1432 } else {
1433 $$ = CreateIRT($1,$3,g_typeargs);
1434 }
1435 } else {
1436 error_reporter_current_line(ASC_USER_ERROR,"The IS_REFINED_TO uses the undefined type %s.\n",SCP($3));
1437 DestroyVariableList($1);
1438 DestroySetList(g_typeargs);
1439 g_untrapped_error++;
1440 $$ = NULL;
1441 }
1442 g_typeargs = NULL;
1443 }
1444 ;
1445
1446 call_identifier:
1447 IDENTIFIER_TOK
1448 {
1449 $$ = $1;
1450 g_callargs = NULL;
1451 }
1452 | IDENTIFIER_TOK '(' set ')'
1453 {
1454 $$ = $1;
1455 g_callargs = $3;
1456 }
1457 ;
1458
1459 type_identifier:
1460 IDENTIFIER_TOK
1461 {
1462 $$ = $1;
1463 g_typeargs = NULL;
1464 }
1465 | IDENTIFIER_TOK '(' set ')'
1466 {
1467 $$ = $1;
1468 g_typeargs = $3;
1469 }
1470 ;
1471
1472 optional_method:
1473 /* empty */
1474 {
1475 $$ = NULL;
1476 }
1477 | METHOD_TOK IDENTIFIER_TOK
1478 {
1479 $$ = $2;
1480 }
1481 ;
1482
1483 optional_of:
1484 /* empty */
1485 {
1486 $$ = NULL;
1487 }
1488 | OF_TOK IDENTIFIER_TOK
1489 {
1490 $$ = $2;
1491 }
1492 ;
1493
1494 optional_with_value:
1495 /* empty */
1496 {
1497 $$ = NULL;
1498 }
1499 | WITH_VALUE_T expr
1500 {
1501 $$ = $2;
1502 }
1503 ;
1504
1505 arealike_statement:
1506 fvarlist AREALIKE_TOK
1507 {
1508 $$ = CreateAA($1);
1509 }
1510 ;
1511
1512 arethesame_statement:
1513 fvarlist ARETHESAME_TOK
1514 {
1515 $$ = CreateATS($1);
1516 }
1517 ;
1518
1519 willbethesame_statement:
1520 fvarlist WILLBETHESAME_TOK
1521 {
1522 $$ = CreateWBTS($1);
1523 }
1524 ;
1525
1526 willnotbethesame_statement:
1527 fvarlist WILLNOTBETHESAME_TOK
1528 {
1529 $$ = CreateWNBTS($1);
1530 }
1531 ;
1532
1533 assignment_statement:
1534 fname ASSIGN_TOK expr
1535 {
1536 $$ = CreateASSIGN($1,$3);
1537 }
1538 | fname CASSIGN_TOK expr
1539 {
1540 $$ = CreateCASSIGN($1,$3);
1541 }
1542 ;
1543
1544 relation_statement:
1545 relation
1546 {
1547 if (IsRelation($1)) {
1548 if (g_parse_relns == 0) {
1549 DestroyExprList($1);
1550 $$ = NULL;
1551 } else {
1552 $$ = CreateREL(NULL,$1);
1553 }
1554 } else {
1555 $$ = CreateLOGREL(NULL,$1);
1556 }
1557 }
1558 | fname ':' relation
1559 {
1560 if (IsRelation($3)) {
1561 if (g_parse_relns == 0) {
1562 DestroyExprList($3);
1563 DestroyName($1);
1564 $$ = NULL;
1565 } else {
1566 $$ = CreateREL($1,$3);
1567 }
1568 } else {
1569 $$ = CreateLOGREL($1,$3);
1570 }
1571 }
1572 ;
1573
1574 relation:
1575 expr
1576 {
1577 $$ = $1;
1578 if (NumberOfRelOps($1) < 1) {
1579 /* want at least 1. restriction to exactly 1 is in typelint */
1580 ErrMsg_Generic("Missing punctuation (,;:) or else expression contains the \
1581 wrong number of relation operators (=, ==, <, >, <=, >=, !=) preceeding or.");
1582 g_untrapped_error++;
1583 }
1584 }
1585 | MINIMIZE_TOK expr
1586 {
1587 $$ = JoinExprLists($2,CreateOpExpr(e_minimize));
1588 if (NumberOfRelOps($2) > 0) {
1589 ErrMsg_Generic("Objective function contains relation operators (=, ==, <, >, <=, >=, !=).");
1590 g_untrapped_error++;
1591 }
1592 }
1593 | MAXIMIZE_TOK expr
1594 {
1595 $$ = JoinExprLists($2,CreateOpExpr(e_maximize));
1596 if (NumberOfRelOps($2)>0) {
1597 ErrMsg_Generic("Objective function contains relation operators (=, ==, <, >, <=, >=, !=).");
1598 g_untrapped_error++;
1599 }
1600 }
1601 ;
1602
1603 blackbox_statement:
1604 fname ':' IDENTIFIER_TOK '(' input_args ';' output_args data_args ')'
1605 {
1606 /*
1607 * This is the blackbox declarative external relation.
1608 */
1609 struct VariableList *vl;
1610 /*determine the number of variables declared in input_args and output_args*/
1611 unsigned long n_inputs, n_outputs;
1612 n_inputs = VariableListLength($5);
1613 n_outputs = VariableListLength($7);
1614 /*continue with normal parsing process */
1615 vl = JoinVariableLists($5,$7);
1616 /* $$ = CreateEXTERN(2,$1,SCP($3),vl,$8,NULL); */
1617
1618 /*$$ = CreateEXTERNBlackBox($1,SCP($3),vl,$8); //original */
1619 //statement now also knows how many of the variables in vl are inputs/outputs
1620 $$ = CreateEXTERNBlackBox($1,SCP($3),vl,$8,n_inputs,n_outputs);
1621 }
1622 ;
1623
1624 input_args:
1625 fvarlist ':' INPUT_TOK
1626 {
1627 $$ = $1;
1628 }
1629 ;
1630
1631 output_args:
1632 fvarlist ':' OUTPUT_TOK
1633 {
1634 $$ = $1;
1635 }
1636 ;
1637
1638 data_args:
1639 /* empty */
1640 {
1641 $$ = NULL;
1642 }
1643 | ';' fname ':' DATA_TOK
1644 {
1645 $$ = $2;
1646 }
1647 ;
1648
1649 glassbox_statement:
1650 fname ':' IDENTIFIER_TOK '(' fvarlist ';' INTEGER_TOK ')' optional_scope
1651 {
1652 /*
1653 * This is the glassbox declarative external relation.
1654 * This now allows a scope for placement of the relations
1655 */
1656 struct VariableList *vl = $5;
1657 struct Name *nptr;
1658 char tmp[32];
1659 symchar *str;
1660
1661 sprintf(tmp,"%ld",$7);
1662 str = AddSymbol(tmp);
1663 nptr = CreateIdName(str);
1664 /* $$ = CreateEXTERN(1,$1,SCP($3),vl,nptr,$9); */
1665 $$ = CreateEXTERNGlassBox($1,SCP($3),vl,nptr,$9);
1666 }
1667 ;
1668
1669 optional_scope:
1670 /* empty */
1671 {
1672 $$ = NULL;
1673 }
1674 | IN_TOK fname
1675 {
1676 $$ = $2;
1677 }
1678 ;
1679
1680 for_statement:
1681 FOR_TOK IDENTIFIER_TOK IN_TOK expr optional_direction forexprend
1682 fstatements end
1683 {
1684 if( $8 != FOR_TOK ) {
1685 WarnMsg_MismatchEnd("FOR", SCP($2), $8, NULL);
1686 }
1687 if ($6 == fk_create && $5 != f_random) {
1688 /* create cannot have an order in declarative FOR */
1689 ErrMsg_Generic("FOR loops only accept DECREASING or INCREASING in the method section.");
1690 g_untrapped_error++;
1691 }
1692 if ($6 == fk_do && $5 == f_random) {
1693 /* all FOR/DO default to increasing */
1694 $$ = CreateFOR($2,$4,$7,f_increasing,$6);
1695 } else {
1696 $$ = CreateFOR($2,$4,$7,$5,$6);
1697 }
1698 }
1699 ;
1700
1701 optional_direction:
1702 /* empty */
1703 {
1704 $$ = f_random;
1705 }
1706 | INCREASING_TOK
1707 {
1708 $$ = f_increasing;
1709 }
1710 | DECREASING_TOK
1711 {
1712 $$ = f_decreasing;
1713 }
1714 ;
1715
1716 forexprend:
1717 CREATE_TOK
1718 {
1719 $$ = fk_create; /* declarative FOR */
1720 }
1721 | EXPECT_TOK
1722 {
1723 $$ = fk_expect; /* parameter FOR */
1724 }
1725 | CHECK_TOK
1726 {
1727 $$ = fk_check; /* WHERE FOR */
1728 }
1729 | DO_TOK
1730 {
1731 $$ = fk_do; /* method FOR */
1732 }
1733 ;
1734
1735 run_statement:
1736 RUN_TOK fname
1737 {
1738 $$ = CreateRUN($2,NULL);
1739 }
1740 | RUN_TOK fname DBLCOLON_TOK fname
1741 {
1742 $$ = CreateRUN($4,$2); /* type :: name */
1743 }
1744 ;
1745
1746 fix_statement:
1747 FIX_TOK fvarlist
1748 {
1749 /*CONSOLE_DEBUG("GOT 'FIX' STATEMENT...");*/
1750 $$ = CreateFIX($2);
1751 }
1752 ;
1753
1754 free_statement:
1755 FREE_TOK fvarlist
1756 {
1757 $$ = CreateFREE($2);
1758 }
1759 ;
1760
1761 solver_statement:
1762 SOLVER_TOK IDENTIFIER_TOK
1763 {
1764 /*CONSOLE_DEBUG("GOT 'SOLVER' STATEMENT WITH '%s'", SCP($2));*/
1765 $$ = CreateSOLVER(SCP($2));
1766 }
1767 ;
1768
1769 option_statement:
1770 OPTION_TOK IDENTIFIER_TOK expr
1771 {
1772 /*CONSOLE_DEBUG("GOT 'OPTION' STATEMENT WITH '%s'", SCP($2));*/
1773 $$ = CreateOPTION(SCP($2),$3);
1774 }
1775 ;
1776
1777 solve_statement:
1778 SOLVE_TOK
1779 {
1780 /*CONSOLE_DEBUG("GOT 'SOLVE' STATEMENT");*/
1781 $$ = CreateSOLVE();
1782 }
1783 ;
1784
1785 external_statement:
1786 EXTERNAL_TOK IDENTIFIER_TOK '(' fvarlist ')'
1787 {
1788 /*
1789 * This is procedural external code. Was:
1790 $$ = CreateEXTERN(0,NULL,SCP($2),$4,NULL,NULL);
1791 */
1792 $$ = CreateEXTERNMethod(SCP($2),$4);
1793 }
1794 ;
1795
1796 call_statement:
1797 CALL_TOK call_identifier
1798 {
1799 /*
1800 * This is proper procedural external method code.
1801 */
1802 $$ = CreateCALL($2,g_callargs);
1803 g_callargs = NULL;
1804 }
1805 ;
1806
1807 assert_statement:
1808 ASSERT_TOK expr
1809 {
1810 $$ = CreateASSERT($2);
1811 }
1812
1813 if_statement:
1814 IF_TOK expr THEN_TOK fstatements optional_else end
1815 {
1816 if( $6 != IF_TOK ) {
1817 WarnMsg_MismatchEnd("IF", NULL, $6, NULL);
1818 }
1819 $$ = CreateIF($2,$4,$5);
1820 }
1821 ;
1822
1823 while_statement:
1824 WHILE_TOK expr DO_TOK fstatements end
1825 {
1826 if( $5 != WHILE_TOK ) {
1827 WarnMsg_MismatchEnd("WHILE", NULL, $5, NULL);
1828 }
1829 $$ = CreateWhile($2,$4);
1830 }
1831 ;
1832
1833 optional_else:
1834 {
1835 $$ = NULL;
1836 }
1837 | ELSE_TOK fstatements
1838 {
1839 $$ = $2;
1840 }
1841 ;
1842
1843 when_statement:
1844 WHEN_TOK fvarlist whenlist end
1845 {
1846 if( $4 != WHEN_TOK ) {
1847 WarnMsg_MismatchEnd("WHEN", NULL, $4, NULL);
1848 }
1849 ErrMsg_Generic("() missing in WHEN statement.");
1850 DestroyWhenList($3);
1851 DestroyVariableList($2);
1852 g_untrapped_error++;
1853 $$ = NULL;
1854 }
1855 | fname ':' WHEN_TOK fvarlist whenlist end
1856 {
1857 if( $6 != WHEN_TOK ) {
1858 WarnMsg_MismatchEnd("WHEN", NULL, $6, NULL);
1859 }
1860 ErrMsg_Generic("() missing in WHEN statement.");
1861 DestroyWhenList($5);
1862 DestroyVariableList($4);
1863 DestroyName($1);
1864 g_untrapped_error++;
1865 $$ = NULL;
1866 }
1867 | WHEN_TOK '(' fvarlist ')' whenlist end
1868 {
1869 if( $6 != WHEN_TOK ) {
1870 WarnMsg_MismatchEnd("WHEN", NULL, $6, NULL);
1871 }
1872 $$ = CreateWHEN(NULL,$3,$5);
1873 }
1874 | fname ':' WHEN_TOK '(' fvarlist ')' whenlist end
1875 {
1876 if( $8 != WHEN_TOK ) {
1877 WarnMsg_MismatchEnd("WHEN", NULL, $8, NULL);
1878 }
1879 $$ = CreateWHEN($1,$5,$7);
1880 }
1881 ;
1882
1883 whenlist:
1884 whenlistf
1885 {
1886 $$ = ReverseWhenCases($1);
1887 }
1888 ;
1889
1890 whenlistf:
1891 CASE_TOK set ':' fstatements
1892 {
1893 $$ = CreateWhen($2,$4);
1894 }
1895 | OTHERWISE_TOK ':' fstatements
1896 {
1897 $$ = CreateWhen(NULL,$3);
1898 }
1899 | whenlistf CASE_TOK set ':' fstatements
1900 {
1901 $$ = LinkWhenCases(CreateWhen($3,$5),$1);
1902 }
1903 | whenlistf OTHERWISE_TOK ':' fstatements
1904 {
1905 $$ = LinkWhenCases(CreateWhen(NULL,$4),$1);
1906 }
1907 ;
1908
1909 flow_statement:
1910 BREAK_TOK
1911 {
1912 $$ = CreateFlow(fc_break,NULL);
1913 }
1914 | CONTINUE_TOK
1915 {
1916 $$ = CreateFlow(fc_continue,NULL);
1917 }
1918 | FALLTHRU_TOK
1919 {
1920 $$ = CreateFlow(fc_fallthru,NULL);
1921 }
1922 | RETURN_TOK
1923 {
1924 $$ = CreateFlow(fc_return,NULL);
1925 }
1926 | STOP_TOK optional_bracedtext
1927 {
1928 $$ = CreateFlow(fc_stop,$2);
1929 }
1930 ;
1931
1932 use_statement:
1933 USE_TOK fname
1934 {
1935 $$ = CreateFNAME($2);
1936 }
1937 ;
1938
1939 select_statement:
1940 SELECT_TOK fvarlist selectlist end
1941 {
1942 if( $4 != SELECT_TOK ) {
1943 WarnMsg_MismatchEnd("SELECT", NULL, $4, NULL);
1944 }
1945 ErrMsg_Generic("() missing in SELECT statement.");
1946 DestroySelectList($3);
1947 DestroyVariableList($2);
1948 g_untrapped_error++;
1949 $$ = NULL;
1950 }
1951 | SELECT_TOK '(' fvarlist ')' selectlist end
1952 {
1953 if( $6 != SELECT_TOK ) {
1954 WarnMsg_MismatchEnd("SELECT", NULL, $6, NULL);
1955 }
1956 $$ = CreateSELECT($3,$5);
1957 }
1958 ;
1959
1960 selectlist:
1961 selectlistf
1962 {
1963 $$ = ReverseSelectCases($1);
1964 }
1965 ;
1966
1967 selectlistf:
1968 CASE_TOK set ':' fstatements
1969 {
1970 $$ = CreateSelect($2,$4);
1971 }
1972 | OTHERWISE_TOK ':' fstatements
1973 {
1974 $$ = CreateSelect(NULL,$3);
1975 }
1976 | selectlistf CASE_TOK set ':' fstatements
1977 {
1978 $$ = LinkSelectCases(CreateSelect($3,$5),$1);
1979 }
1980 | selectlistf OTHERWISE_TOK ':' fstatements
1981 {
1982 $$ = LinkSelectCases(CreateSelect(NULL,$4),$1);
1983 }
1984 ;
1985
1986 switch_statement:
1987 SWITCH_TOK fvarlist switchlist end
1988 {
1989 if( $4 != SWITCH_TOK ) {
1990 WarnMsg_MismatchEnd("SWITCH", NULL, $4, NULL);
1991 }
1992 ErrMsg_Generic("() missing in SWITCH statement.");
1993 DestroySwitchList($3);
1994 DestroyVariableList($2);
1995 g_untrapped_error++;
1996 $$ = NULL;
1997 }
1998 | SWITCH_TOK '(' fvarlist ')' switchlist end
1999 {
2000 if( $6 != SWITCH_TOK ) {
2001 WarnMsg_MismatchEnd("SWITCH", NULL, $6, NULL);
2002 }
2003 $$ = CreateSWITCH($3,$5);
2004 }
2005 ;
2006
2007 switchlist:
2008 switchlistf
2009 {
2010 $$ = ReverseSwitchCases($1);
2011 }
2012 ;
2013
2014 switchlistf:
2015 CASE_TOK set ':' fstatements
2016 {
2017 $$ = CreateSwitch($2,$4);
2018 }
2019 | OTHERWISE_TOK ':' fstatements
2020 {
2021 $$ = CreateSwitch(NULL,$3);
2022 }
2023 | switchlistf CASE_TOK set ':' fstatements
2024 {
2025 $$ = LinkSwitchCases(CreateSwitch($3,$5),$1);
2026 }
2027 | switchlistf OTHERWISE_TOK ':' fstatements
2028 {
2029 $$ = LinkSwitchCases(CreateSwitch(NULL,$4),$1);
2030 }
2031 ;
2032
2033 conditional_statement:
2034 CONDITIONAL_TOK fstatements end
2035 {
2036 if( $3 != CONDITIONAL_TOK ) {
2037 WarnMsg_MismatchEnd("CONDITIONAL", NULL, $3, NULL);
2038 }
2039 $$ = CreateCOND($2);
2040 }
2041 ;
2042
2043 notes_statement:
2044 NOTES_TOK notes_body end
2045 {
2046 /* All processing of notes takes place on the notes_body here.
2047 * Notes should NOT be added to the statement list.
2048 * Here we know the current type and method names.
2049 */
2050 if( $3 != NOTES_TOK ) {
2051 WarnMsg_MismatchEnd("NOTES", NULL, $3, NULL);
2052 }
2053 if ($2 != NULL) {
2054 struct NoteTmp *nt;
2055 symchar *lang=NULL; /* dummy */
2056 nt = $2;
2057 while (nt != NULL) {
2058 if (nt->lang != NULL) {
2059 /* this logic works because of the reverse sort that
2060 * yacc does via noteslist and the forward sort that
2061 * we do via notesbody. lang recorded last appears
2062 * before other entries that need it.
2063 */
2064 lang = nt->lang;
2065 }
2066
2067 /* save exploding vardata to simple entries until we keep */
2068 CollectNote(CreateNote(g_type_name, lang, NULL, g_proc_name,
2069 Asc_ModuleBestName(Asc_CurrentModule()),
2070 nt->bt,
2071 nt->line, nt->vardata, nd_vlist));
2072 nt = nt->next;
2073 }
2074 DestroyNoteTmpList($2);
2075 }
2076 $$ = NULL;
2077 }
2078 ;
2079
2080 notes_body:
2081 SYMBOL_TOK noteslist
2082 {
2083 /* At this point we have the "language", the names of the
2084 * objects we are explaining, and the explanation/notes itself.
2085 */
2086 $$ = $2;
2087 assert($$->lang == NULL);
2088 $$->lang = $1;
2089 }
2090 | notes_body SYMBOL_TOK noteslist
2091 {
2092 struct NoteTmp *nt;
2093 $$ = $1;
2094 assert($3->lang == NULL);
2095 $3->lang = $2;
2096 nt = $$;
2097 while (nt->next != NULL) {
2098 nt = nt->next;
2099 }
2100 LinkNoteTmp(nt,$3);
2101 }
2102 ;
2103
2104 noteslist:
2105 fvarlist BRACEDTEXT_TOK
2106 {
2107 $$ = CreateNoteTmp(NULL, AddBraceChar($2,NULL),
2108 (void *)$1, LineNum());
2109 }
2110 | noteslist fvarlist BRACEDTEXT_TOK
2111 {
2112 $$ = CreateNoteTmp(NULL, AddBraceChar($3,NULL),
2113 (void *)$2, LineNum());
2114 LinkNoteTmp($$,$1);
2115 }
2116 ;
2117
2118 fvarlist:
2119 varlist
2120 {
2121 /*
2122 * Reversing the variable list is now essential to deal with
2123 * external procedures and other things where order is important.
2124 */
2125 $$ = ReverseVariableList($1);
2126 }
2127 ;
2128
2129 varlist:
2130 fname
2131 {
2132 $$ = CreateVariableNode($1);
2133 }
2134 | varlist ',' fname
2135 {
2136 $$ = CreateVariableNode($3);
2137 LinkVariableNodes($$,$1);
2138 }
2139 | varlist fname
2140 {
2141 ErrMsg_CommaName("name",$2);
2142 $$ = CreateVariableNode($2);
2143 LinkVariableNodes($$,$1);
2144 /* trash the definition. keep the loose fname around because
2145 * destroying here is inconvenient
2146 */
2147 g_untrapped_error++;
2148 }
2149 ;
2150
2151 fname:
2152 name optional_notes
2153 {
2154 symchar *simple;
2155 void *data;
2156 enum NoteData nd;
2157 $$ = ReverseName($1);
2158 if ($2 != NULL && $1 != NULL) {
2159 simple = SimpleNameIdPtr($$);
2160 data = (simple == NULL ? (void *)$$ : NULL);
2161 nd = (data == NULL ? nd_empty : nd_name);
2162 CollectNote(CreateNote(g_type_name, InlineNote(), simple,
2163 g_proc_name,
2164 Asc_ModuleBestName(Asc_CurrentModule()),
2165 AddBraceChar($2,InlineNote()),
2166 LineNum(), data, nd));
2167 }
2168 }
2169 ;
2170
2171 name:
2172 IDENTIFIER_TOK
2173 {
2174 $$ = CreateIdName($1);
2175 }
2176 | name '.' IDENTIFIER_TOK
2177 {
2178 $$ = CreateIdName($3);
2179 LinkNames($$,$1);
2180 }
2181 | name '[' set ']'
2182 {
2183 if ($3 == NULL) {
2184 error_reporter_current_line(ASC_USER_ERROR,"syntax error: Empty set in name definition, name:");
2185 WriteName(ASCERR,$1);
2186 FPRINTF(ASCERR,"[]\n");
2187 g_untrapped_error++;
2188 } else {
2189 $$ = CreateSetName($3);
2190 LinkNames($$,$1);
2191 }
2192 }
2193 ;
2194
2195 end:
2196 END_TOK CONDITIONAL_TOK
2197 {
2198 g_end_identifier = NULL;
2199 $$ = CONDITIONAL_TOK;
2200 }
2201 | END_TOK FOR_TOK
2202 {
2203 g_end_identifier = NULL;
2204 $$ = FOR_TOK;
2205 }
2206 | END_TOK IF_TOK
2207 {
2208 g_end_identifier = NULL;
2209 $$ = IF_TOK;
2210 }
2211 | END_TOK INTERACTIVE_TOK
2212 {
2213 g_end_identifier = NULL;
2214 $$ = INTERACTIVE_TOK;
2215 }
2216 | END_TOK METHODS_TOK
2217 {
2218 g_end_identifier = NULL;
2219 $$ = METHODS_TOK;
2220 }
2221 | END_TOK NOTES_TOK
2222 {
2223 g_end_identifier = NULL;
2224 $$ = NOTES_TOK;
2225 }
2226 | END_TOK SELECT_TOK
2227 {
2228 g_end_identifier = NULL;
2229 $$ = SELECT_TOK;
2230 }
2231 | END_TOK SWITCH_TOK
2232 {
2233 g_end_identifier = NULL;
2234 $$ = SWITCH_TOK;
2235 }
2236 | END_TOK UNITS_TOK
2237 {
2238 g_end_identifier = NULL;
2239 $$ = UNITS_TOK;
2240 }
2241 | END_TOK GLOBAL_TOK
2242 {
2243 g_end_identifier = NULL;
2244 $$ = GLOBAL_TOK;
2245 }
2246 | END_TOK WHEN_TOK
2247 {
2248 g_end_identifier = NULL;
2249 $$ = WHEN_TOK;
2250 }
2251 | END_TOK WHILE_TOK
2252 {
2253 g_end_identifier = NULL;
2254 $$ = WHILE_TOK;
2255 }
2256 | END_TOK IDENTIFIER_TOK
2257 {
2258 g_end_identifier = $2;
2259 $$ = IDENTIFIER_TOK;
2260 }
2261 | END_TOK /* empty */
2262 {
2263 g_end_identifier = NULL;
2264 $$ = END_TOK;
2265 }
2266 ;
2267
2268 optional_bracedtext:
2269 /* empty */
2270 {
2271 $$ = NULL;
2272 }
2273 | BRACEDTEXT_TOK
2274 {
2275 $$ = $1;
2276 }
2277 ;
2278
2279 optional_notes:
2280 /* empty */
2281 {
2282 $$ = NULL;
2283 }
2284 | DQUOTE_TOK
2285 {
2286 $$ = $1;
2287 }
2288 ;
2289
2290 set:
2291 setexprlist
2292 {
2293 $$ = ReverseSetList($1);
2294 }
2295 | /* empty */
2296 {
2297 $$ = NULL;
2298 }
2299 ;
2300
2301 setexprlist:
2302 expr
2303 {
2304 $$ = CreateSingleSet($1);
2305 }
2306 | expr DOTDOT_TOK expr
2307 {
2308 $$ = CreateRangeSet($1,$3);
2309 }
2310 | setexprlist ',' expr
2311 {
2312 $$ = CreateSingleSet($3);
2313 LinkSets($$,$1);
2314 }
2315 | setexprlist ',' expr DOTDOT_TOK expr
2316 {
2317 $$ = CreateRangeSet($3,$5);
2318 LinkSets($$,$1);
2319 }
2320 ;
2321
2322 number:
2323 INTEGER_TOK
2324 {
2325 $$ = $1;
2326 g_constant_type = LONGCONSTANT;
2327 g_default_dim_ptr = Dimensionless();
2328 }
2329 | realnumber
2330 {
2331 $$ = $1;
2332 g_constant_type = DOUBLECONSTANT;
2333 g_default_dim_ptr = g_dim_ptr;
2334 }
2335 ;
2336
2337 realnumber:
2338 REAL_TOK opunits
2339 {
2340 $$ = $1*$2;
2341 }
2342 | INTEGER_TOK BRACEDTEXT_TOK
2343 {
2344 unsigned long pos;
2345 int error_code;
2346 g_units_ptr = FindOrDefineUnits($2,&pos,&error_code);
2347 if (g_units_ptr != NULL) {
2348 $$ = (double)$1*UnitsConvFactor(g_units_ptr);
2349 g_dim_ptr = UnitsDimensions(g_units_ptr);
2350 } else {
2351 char **errv;
2352 $$ = (double)$1;
2353 g_dim_ptr = WildDimension();
2354 error_reporter_current_line(ASC_USER_ERROR,"Undefined units '%s'", $2);
2355 errv = UnitsExplainError($2,error_code,pos);
2356 error_reporter_current_line(ASC_USER_ERROR," %s\n %s\n %s\n",errv[0],errv[1],errv[2]);
2357 g_untrapped_error++;
2358 }
2359 }
2360 ;
2361
2362 opunits:
2363 /* empty */
2364 {
2365 g_dim_ptr = Dimensionless();
2366 $$ = 1.0;
2367 }
2368 | BRACEDTEXT_TOK
2369 {
2370 unsigned long pos;
2371 int error_code;
2372 g_units_ptr = FindOrDefineUnits($1,&pos,&error_code);
2373 if (g_units_ptr != NULL) {
2374 $$ = UnitsConvFactor(g_units_ptr);
2375 g_dim_ptr = UnitsDimensions(g_units_ptr);
2376 } else {
2377 char **errv;
2378 $$ = 1.0;
2379 g_dim_ptr = WildDimension();
2380 error_reporter_current_line(ASC_USER_ERROR,"Undefined units '%s'",$1);
2381 errv = UnitsExplainError($1,error_code,pos);
2382 error_reporter_current_line(ASC_USER_ERROR," %s\n %s\n %s\n",errv[0],errv[1],errv[2]);
2383 g_untrapped_error++;
2384 }
2385 }
2386 ;
2387
2388 dims:
2389 DIMENSION_TOK dimensions
2390 {
2391 $$ = $2;
2392 }
2393 | DIMENSIONLESS_TOK
2394 {
2395 $$ = Dimensionless();
2396 }
2397 | /* empty */
2398 {
2399 $$ = WildDimension();
2400 }
2401 ;
2402
2403 dimensions:
2404 '*'
2405 {
2406 $$ = WildDimension();
2407 }
2408 | dimexpr
2409 {
2410 $$ = FindOrAddDimen(&($1));
2411 }
2412 ;
2413
2414 dimexpr:
2415 IDENTIFIER_TOK
2416 {
2417 ParseDim(&($$),SCP($1));
2418 }
2419 | INTEGER_TOK
2420 {
2421 ClearDimensions(&($$));
2422 }
2423 | dimexpr '/' dimexpr
2424 {
2425 $$ = SubDimensions(&($1),&($3));
2426 }
2427 | dimexpr '*' dimexpr
2428 {
2429 $$ = AddDimensions(&($1),&($3));
2430 }
2431 | dimexpr '^' fraction
2432 {
2433 $$ = ScaleDimensions(&($1),$3);
2434 }
2435 | '(' dimexpr ')'
2436 {
2437 CopyDimensions(&($2),&($$));
2438 }
2439 ;
2440
2441 fraction:
2442 optional_sign fractail
2443 {
2444 $$ = $1 ? NegateF($2) : $2;
2445 }
2446 ;
2447
2448 fractail:
2449 INTEGER_TOK
2450 {
2451 $$ = CreateFraction((short)$1,(short)1);
2452 }
2453 | '(' INTEGER_TOK '/' INTEGER_TOK ')'
2454 {
2455 $$ = CreateFraction((short)$2,(short)$4);
2456 }
2457 ;
2458
2459 optional_sign:
2460 /* empty */
2461 {
2462 $$ = 0;
2463 }
2464 | '+'
2465 {
2466 $$ = 0;
2467 }
2468 | '-'
2469 {
2470 $$ = 1;
2471 }
2472 ;
2473
2474 expr:
2475 INTEGER_TOK
2476 {
2477 $$ = CreateIntExpr($1);
2478 }
2479 | MAXINTEGER_TOK
2480 {
2481 $$ = CreateIntExpr(LONG_MAX-1);
2482 }
2483 | realnumber
2484 {
2485 $$ = CreateRealExpr($1,g_dim_ptr);
2486 }
2487 | MAXREAL_TOK
2488 {
2489 $$ = CreateRealExpr(DBL_MAX/(1+1e-15),Dimensionless());
2490 }
2491 | TRUE_TOK
2492 {
2493 $$ = CreateTrueExpr();
2494 }
2495 | FALSE_TOK
2496 {
2497 $$ = CreateFalseExpr();
2498 }
2499 | ANY_TOK
2500 {
2501 $$ = CreateAnyExpr();
2502 }
2503 | SYMBOL_TOK
2504 {
2505 $$ = CreateSymbolExpr($1);
2506 }
2507 | fname
2508 {
2509 $$ = CreateVarExpr($1);
2510 }
2511 | '[' set ']'
2512 {
2513 $$ = CreateSetExpr($2);
2514 }
2515 | expr '+' expr
2516 {
2517 $3 = JoinExprLists($3,CreateOpExpr(e_plus));
2518 $$ = JoinExprLists($1,$3);
2519 }
2520 | expr '-' expr
2521 {
2522 $3 = JoinExprLists($3,CreateOpExpr(e_minus));
2523 $$ = JoinExprLists($1,$3);
2524 }
2525 | expr '*' expr
2526 {
2527 $3 = JoinExprLists($3,CreateOpExpr(e_times));
2528 $$ = JoinExprLists($1,$3);
2529 }
2530 | expr '/' expr
2531 {
2532 $3 = JoinExprLists($3,CreateOpExpr(e_divide));
2533 $$ = JoinExprLists($1,$3);
2534 }
2535 | expr '^' expr
2536 {
2537 $3 = JoinExprLists($3,CreateOpExpr(e_power));
2538 $$ = JoinExprLists($1,$3);
2539 }
2540 | expr AND_TOK expr
2541 {
2542 $3 = JoinExprLists($3,CreateOpExpr(e_and));
2543 $$ = JoinExprLists($1,$3);
2544 }
2545 | expr OR_TOK expr
2546 {
2547 $3 = JoinExprLists($3,CreateOpExpr(e_or));
2548 $$ = JoinExprLists($1,$3);
2549 }
2550 | NOT_TOK expr
2551 {
2552 $$ = JoinExprLists($2,CreateOpExpr(e_not));
2553 }
2554 | expr relop expr %prec NEQ_TOK
2555 {
2556 $3 = JoinExprLists($3,$2);
2557 $$ = JoinExprLists($1,$3);
2558 }
2559 | expr logrelop expr %prec BEQ_TOK
2560 {
2561 $3 = JoinExprLists($3,$2);
2562 $$ = JoinExprLists($1,$3);
2563 }
2564 | expr IN_TOK expr
2565 {
2566 $3 = JoinExprLists($3,CreateOpExpr(e_in));
2567 $$ = JoinExprLists($1,$3);
2568 }
2569 | expr '|' expr
2570 {
2571 $3 = JoinExprLists($3,CreateOpExpr(e_st));
2572 $$ = JoinExprLists($1,$3);
2573 }
2574 | expr SUCHTHAT_TOK expr
2575 {
2576 $3 = JoinExprLists($3,CreateOpExpr(e_st));
2577 $$ = JoinExprLists($1,$3);
2578 }
2579 | '+' expr %prec UPLUS_TOK
2580 {
2581 $$ = $2;
2582 }
2583 | '-' expr %prec UMINUS_TOK
2584 {
2585 $$ = JoinExprLists($2,CreateOpExpr(e_uminus));
2586 }
2587 | SATISFIED_TOK '(' fname ',' realnumber ')'
2588 {
2589 $$ = CreateSatisfiedExpr($3,$5,g_dim_ptr);
2590 }
2591 | SATISFIED_TOK '(' fname ')'
2592 {
2593 $$ = CreateSatisfiedExpr($3,DBL_MAX,NULL);
2594 }
2595 | SUM_TOK '(' set ')'
2596 {
2597 DestroySetList($3);
2598 $$ = NULL;
2599 ErrMsg_ParensBrackets("SUM");
2600 g_untrapped_error++;
2601 }
2602 | SUM_TOK '[' set ']'
2603 {
2604 $$ = CreateBuiltin(e_sum,$3);
2605 }
2606 | PROD_TOK '(' set ')'
2607 {
2608 DestroySetList($3);
2609 $$ = NULL;
2610 ErrMsg_ParensBrackets("PROD");
2611 g_untrapped_error++;
2612 }
2613 | PROD_TOK '[' set ']'
2614 {
2615 $$ = CreateBuiltin(e_prod,$3);
2616 }
2617 | UNION_TOK '(' set ')'
2618 {
2619 DestroySetList($3);
2620 $$ = NULL;
2621 ErrMsg_ParensBrackets("UNION");
2622 g_untrapped_error++;
2623 }
2624 | UNION_TOK '[' set ']'
2625 {
2626 $$ = CreateBuiltin(e_union,$3);
2627 }
2628 | INTERSECTION_TOK '(' set ')'
2629 {
2630 DestroySetList($3);
2631 $$ = NULL;
2632 ErrMsg_ParensBrackets("INTERSECTION");
2633 g_untrapped_error++;
2634 }
2635 | INTERSECTION_TOK '[' set ']'
2636 {
2637 $$ = CreateBuiltin(e_inter,$3);
2638 }
2639 | CARD_TOK '(' set ')'
2640 {
2641 DestroySetList($3);
2642 $$ = NULL;
2643 ErrMsg_ParensBrackets("CARD");
2644 g_untrapped_error++;
2645 }
2646 | CARD_TOK '[' set ']'
2647 {
2648 $$ = CreateBuiltin(e_card,$3);
2649 }
2650 | CHOICE_TOK '(' set ')'
2651 {
2652 DestroySetList($3);
2653 $$ = NULL;
2654 ErrMsg_ParensBrackets("CHOICE");
2655 g_untrapped_error++;
2656 }
2657 | CHOICE_TOK '[' set ']'
2658 {
2659 $$ = CreateBuiltin(e_choice,$3);
2660 }
2661 | IDENTIFIER_TOK '(' expr ')'
2662 {
2663 CONST struct Func *fptr;
2664 if ((fptr = LookupFunc(SCP($1)))!=NULL) {
2665 $$ = JoinExprLists($3,CreateFuncExpr(fptr));
2666 } else {
2667 $$ = NULL;
2668 error_reporter_current_line(ASC_USER_ERROR,"Function '%s' is not defined.",SCP($1));
2669 g_untrapped_error++;
2670 }
2671 }
2672 | '(' expr ')'
2673 {
2674 $$ = $2;
2675 }
2676 ;
2677
2678 relop:
2679 '='
2680 {
2681 $$ = CreateOpExpr(e_equal);
2682 }
2683 | '<'
2684 {
2685 $$ = CreateOpExpr(e_less);
2686 }
2687 | '>'
2688 {
2689 $$ = CreateOpExpr(e_greater);
2690 }
2691 | LEQ_TOK /* less than or equal written "<=" */
2692 {
2693 $$ = CreateOpExpr(e_lesseq);
2694 }
2695 | GEQ_TOK /* greater than or equal written ">=" */
2696 {
2697 $$ = CreateOpExpr(e_greatereq);
2698 }
2699 | NEQ_TOK /* not equal written "<>" */
2700 {
2701 $$ = CreateOpExpr(e_notequal);
2702 }
2703 ;
2704
2705 logrelop:
2706 BEQ_TOK /* equality in boolean relations */
2707 {
2708 $$ = CreateOpExpr(e_boolean_eq);
2709 }
2710 | BNE_TOK /* non equality in boolean relations */
2711 {
2712 $$ = CreateOpExpr(e_boolean_neq);
2713 }
2714 ;
2715 %%
2716 /* END OF GRAMMAR RULES
2717 -----------------------------------------------------------------------------
2718 START OF EPILOGUE
2719 */
2720
2721 /*
2722 * We really need to do something about freeing up the productions
2723 * that invoke this so we don't leak memory like a seive.
2724 * for example z[i IN [1..2]][j IN [process[i]] IS_A mass; eats a ton.
2725 */
2726 int
2727 zz_error(char *s){
2728 g_untrapped_error++;
2729 if (Asc_CurrentModule() != NULL) {
2730 error_reporter_current_line(ASC_USER_ERROR,"%s",s);
2731 } else {
2732 error_reporter(ASC_USER_ERROR,NULL,0,NULL,"%s at end of input.",s);
2733 }
2734 return 0;
2735 }
2736
2737 /*
2738 * See the header file scanner.h for a description of this function.
2739 */
2740 void
2741 Asc_ErrMsgTypeDefnEOF(void)
2742 {
2743 /* Check g_type_name to see if we're in the middle of a type
2744 * definition. If NULL no, otherwise yes.
2745 */
2746 if ( g_type_name ) {
2747 error_reporter_current_line(ASC_USER_ERROR,
2748 "End of file reached in a type definition. Incomplete definition for '%s'.",
2749 SCP(g_type_name));
2750 }
2751 }
2752
2753 #define ERRCOUNT_PARSERGENERIC 30
2754 /*
2755 * void ErrMsg_*(void)
2756 *
2757 * The following print error and warning messages to the filehandles
2758 * ASCERR and ASCWARN, respectively.
2759 * The type of error/warning that will be printed is indicated by the
2760 * functions name and the arguments to fprintf.
2761 */
2762 static void ErrMsg_Generic(CONST char *string){
2763 static int errcount=0;
2764 if(errcount<30){
2765 /* the module may have be already closed, Asc_CurrentModule will be null */
2766 error_reporter_current_line(ASC_USER_ERROR,"%s",string);
2767
2768 if (g_type_name != NULL) {
2769 error_reporter_current_line(ASC_USER_ERROR," type %s\n",SCP(g_type_name));
2770 }
2771 if (g_proc_name != NULL) {
2772 error_reporter_current_line(ASC_USER_ERROR," METHOD %s\n",SCP(g_proc_name));
2773 }
2774
2775 errcount++;
2776 if(errcount==30){
2777 ERROR_REPORTER_HERE(ASC_PROG_NOTE
2778 ,"Further reports of this error will be suppressed.\n"
2779 );
2780 }
2781 }
2782 }
2783
2784 static void ErrMsg_CommaName(CONST char *what, struct Name *name)
2785 {
2786 struct module_t *mod;
2787
2788 /* the module may have be already closed */
2789 mod = Asc_CurrentModule();
2790
2791 ERROR_REPORTER_START_HERE(ASC_USER_ERROR);
2792 FPRINTF(ASCERR, "Missing comma or operator before %s '",what);
2793 WriteName(ASCERR,name);
2794 FPRINTF(ASCERR, "'");
2795 error_reporter_end_flush();
2796 }
2797
2798 #if COMMAEXPR_NOTBUGGY
2799 static void ErrMsg_CommaExpr(CONST char *what, struct Expr *eptr)
2800 {
2801 struct module_t *mod;
2802
2803 /* the module may have be already closed */
2804 error_reporter_current_line(ASC_USER_ERROR, "ASC-Error: Missing comma before %s ",what);
2805 WriteExpr(ASCERR,eptr);
2806 }
2807 #endif /* COMMAEXPR_NOTBUGGY. delete if can't fix */
2808
2809 static void
2810 ErrMsg_NullDefPointer(CONST char *object)
2811 {
2812 error_reporter_current_line(ASC_USER_ERROR,"Rejected '%s'", object);
2813 }
2814
2815 static void
2816 ErrMsg_ParensBrackets(CONST char *operation)
2817 {
2818 error_reporter_current_line(ASC_USER_ERROR,
2819 " You should be using %s[] not %s()",
2820 operation,
2821 operation);
2822 }
2823
2824
2825 /**
2826 Print a warning message that the token after the END keyword did not
2827 match what we were expecting for the current statement.
2828
2829 @param statement --the current statement, e.g. ATOM, METHOD, FOR, IF, CASE
2830 @param opt_name --the name of the thing we were defining for ATOMs, METHODs,
2831 etc, or NULL anonymous statements (FOR, IF, CASE, etc)
2832 @param end_token --the TOKEN_TOK that we were received instead. We use the
2833 TokenAsString to produce a string given a TOKEN_TOK
2834 @param expecting --the keyword we were expecting to see after the END; if
2835 NULL, we were expecting the string given in statement
2836 */
2837 static void
2838 WarnMsg_MismatchEnd(CONST char *statement, CONST char *opt_name,
2839 unsigned long end_token, CONST char *expecting)
2840 {
2841 error_reporter_current_line(ASC_USER_WARNING,
2842 "%s %s terminated with 'END %s;', expecting 'END %s;'"
2843 ,statement
2844 ,((opt_name != NULL) ? opt_name : "statement")
2845 ,TokenAsString(end_token)
2846 ,((expecting != NULL) ? expecting : statement));
2847 }
2848
2849
2850 /*
2851 Take a TOKEN_TOK (e.g., FOR_TOK, MODEL_TOK, END_TOK, IDENTIFIER_TOK) and returns
2852 a string representation of it:
2853 e.g.: TokenAsString(FOR_TOK) ==> "FOR"
2854
2855 Since this function is only used inside WarnMsg_MismatchEnd, we do a
2856 couple of things specific to that function: If token is END_TOK, we
2857 return an empty string, and if it is IDENTIFIER_TOK, we return the
2858 current value of g_end_identifier, or UNKNOWN if g_end_identifier is
2859 NULL.
2860 */
2861 static CONST char *
2862 TokenAsString(unsigned long token)
2863 {
2864 switch( token ) {
2865 case ATOM_TOK:
2866 return "ATOM";
2867 case CONDITIONAL_TOK:
2868 return "CONDITIONAL";
2869 case FOR_TOK:
2870 return "FOR";
2871 case ASSERT_TOK:
2872 return "ASSERT";
2873 case IF_TOK:
2874 return "IF";
2875 case INTERACTIVE_TOK:
2876 return "INTERACTIVE";
2877 case METHOD_TOK:
2878 return "METHOD";
2879 case METHODS_TOK:
2880 return "METHODS";
2881 case MODEL_TOK:
2882 return "MODEL";
2883 case NOTES_TOK:
2884 return "NOTES";
2885 case PATCH_TOK:
2886 return "PATCH";
2887 case SELECT_TOK:
2888 return "SELECT";
2889 case SWITCH_TOK:
2890 return "SWITCH";
2891 case UNITS_TOK:
2892 return "UNITS";
2893 case WHEN_TOK:
2894 return "WHEN";
2895 case END_TOK:
2896 return "";
2897 case IDENTIFIER_TOK:
2898 default:
2899 if( g_end_identifier != NULL ) {
2900 return SCP(g_end_identifier);
2901 } else {
2902 return "UNKNOWN";
2903 }
2904 }
2905 }
2906
2907 /* need a refcount game on the text field of the note. must keep
2908 * original note to avoid losing the varlist.
2909 */
2910 static void ProcessNotes(int keep)
2911 {
2912 int c,len;
2913 if (g_notelist == NULL) {
2914 return;
2915 }
2916 if (keep) {
2917 len = gl_length(g_notelist);
2918 for (c=1;c <= len;c++) {
2919 CommitNote(LibraryNote(),gl_fetch(g_notelist,c));
2920 }
2921 } else {
2922 gl_iterate(g_notelist,(void (*) (VOIDPTR))DestroyNote);
2923 }
2924 gl_destroy(g_notelist);
2925 g_notelist = NULL;
2926 }
2927
2928 static void CollectNote(struct Note *n)
2929 {
2930 if (g_notelist == NULL) {
2931 g_notelist = gl_create(50L);
2932 }
2933 if (g_notelist == NULL) {
2934 DestroyNote(n);
2935 return;
2936 }
2937 gl_append_ptr(g_notelist,(VOIDPTR)n);
2938 }
2939
2940 /*
2941 This can be called as error_reporter_current_line(ASC_USER_ERROR,...);
2942 or error_reporter_current_line(ASC_USER_WARNING,...), or with any of the other
2943 severity flags.
2944 */
2945 static void error_reporter_current_line(const error_severity_t sev, const char *fmt,...){
2946 va_list args;
2947 va_start(args,fmt);
2948 va_error_reporter(sev,Asc_ModuleBestName(Asc_CurrentModule()),(int)LineNum(),NULL,fmt,args);
2949 va_end(args);
2950 }

john.pye@anu.edu.au
ViewVC Help
Powered by ViewVC 1.1.22