naspro

view permafrost/src/parser.y @ 178:7169a8909d53

Added Permafrost + small changes
author Stefano D'Angelo <zanga.mail@gmail.com>
date Sun May 02 14:19:58 2010 +0300 (2010-05-02)
parents
children
line source
1 %{
2 /*
3 * Permafrost - Physical modelling framework
4 *
5 * Copyright (C) 2009, 2010 Stefano D'Angelo <zanga.mail@gmail.com>
6 *
7 * See the COPYING file for license conditions.
8 */
10 #include <stdlib.h>
11 #include <stdio.h>
12 #include <string.h>
14 #include "src/types.h"
15 #include "src/util.h"
16 #include "src/list.h"
17 #include "src/expr.h"
18 #include "src/parser.tab.h"
19 #include "src/scanner.h"
20 #include "src/parser.h"
22 void
23 yyerror(YYLTYPE *locp, yyscan_t scanner, const char *filename, char *str)
24 {
25 fprintf(stderr, "%s:%d:%d: error: %s\n", filename, locp->first_line,
26 locp->first_column, str);
27 }
29 /* Comparison functions */
31 static int
32 port_cmp_id(void *p, void *id)
33 {
34 return strcmp(((struct port *)p)->id, (char *)id);
35 }
37 static int
38 conn_elem_cmp(void *e1, void *e2)
39 {
40 struct conn_elem *elem1;
41 struct conn_elem *elem2;
42 int i;
44 elem1 = (struct conn_elem *)e1;
45 elem2 = (struct conn_elem *)e2;
47 if (elem1->type > elem2->type)
48 return 1;
49 if (elem1->type < elem2->type)
50 return -1;
52 if (elem1->type == conn_elem_type_value)
53 return 0;
55 if ((elem1->c.id.component == NULL) && (elem2->c.id.component != NULL))
56 return -1;
57 if ((elem1->c.id.component != NULL) && (elem2->c.id.component == NULL))
58 return 1;
60 if (elem1->c.id.component != NULL)
61 {
62 i = strcmp(elem1->c.id.component, elem2->c.id.component);
63 if (i != 0)
64 return i;
65 }
67 return strcmp(elem1->c.id.port, elem2->c.id.port);
68 }
70 static int
71 connection_cmp(void *c1, void *c2)
72 {
73 struct connection *conn1;
74 struct connection *conn2;
75 int i;
77 conn1 = (struct connection *)c1;
78 conn2 = (struct connection *)c2;
80 i = conn_elem_cmp(&conn1->output, &conn2->output);
82 return (i != 0) ? i : conn_elem_cmp(&conn1->input, &conn2->input);
83 }
85 static int
86 component_cmp_id(void *c, void *id)
87 {
88 return strcmp(((struct component *)c)->id, (char *)id);
89 }
91 static int
92 stmt_cmp_output(void *s1, void *s2)
93 {
94 struct stmt *stmt1;
95 struct stmt *stmt2;
96 int i;
98 stmt1 = (struct stmt *)s1;
99 stmt2 = (struct stmt *)s2;
101 i = strcmp(stmt1->out.id.id, stmt2->out.id.id);
102 if (i != 0)
103 return i;
105 return stmt1->out.id.out ? (stmt2->out.id.out ? 0 : 1)
106 : (stmt2->out.id.out ? -1 : 0);
107 }
109 static int
110 const_cmp_id(void *c, void *id)
111 {
112 return strcmp(((struct const_v *)c)->id, (char *)id);
113 }
115 static int
116 ext_func_cmp_id(void *f, void *id)
117 {
118 return strcmp(((struct ext_func *)f)->id, (char *)id);
119 }
121 static int
122 block_cmp_id(void *b, void *id)
123 {
124 return strcmp(((struct block *)b)->id, (char *)id);
125 }
127 static int
128 system_cmp_id(void *s, void *id)
129 {
130 return strcmp(((struct system *)s)->id, (char *)id);
131 }
133 static int
134 component_cmp_ports_id(void *c, void *p)
135 {
136 struct component *comp;
137 list_t ports;
139 comp = (struct component *)c;
140 ports = (list_t)p;
142 if (list_find(ports, port_cmp_id, comp->id) != NULL)
143 return 0;
145 return 1;
146 }
148 /* Utility functions */
150 struct stmt_defines_port_output_context
151 {
152 const char *filename;
153 YYLTYPE *locp;
154 struct port *port;
155 char defined;
156 };
158 static void
159 stmt_defines_port_output(void *data, void *context)
160 {
161 struct stmt *stmt;
162 struct stmt_defines_port_output_context *ctx;
164 stmt = (struct stmt *)data;
165 ctx = (struct stmt_defines_port_output_context *)context;
167 if (ctx->defined)
168 return;
170 if (!strcmp(stmt->out.id.id, ctx->port->id))
171 {
172 if (stmt->out.id.out && (ctx->port->type != port_type_w)
173 && (ctx->port->type != port_type_k))
174 {
175 fprintf(stderr, "%s:%d:%d: error: port `%s' is not a "
176 "physical port\n", ctx->filename,
177 ctx->locp->first_line, ctx->locp->first_column,
178 stmt->out.id.id);
179 exit(EXIT_FAILURE);
180 }
181 else if (!stmt->out.id.out
182 && (ctx->port->type != port_type_input)
183 && (ctx->port->type != port_type_output))
184 {
185 fprintf(stderr, "%s:%d:%d: error: port `%s' is a "
186 "physical port\n", ctx->filename,
187 ctx->locp->first_line, ctx->locp->first_column,
188 stmt->out.id.id);
189 exit(EXIT_FAILURE);
190 }
192 ctx->defined = 1;
193 }
194 }
196 struct port_output_defined_context
197 {
198 const char *filename;
199 YYLTYPE *locp;
200 list_t stmts;
201 };
203 static void
204 port_output_defined(void *data, void *context)
205 {
206 struct port *port;
207 struct port_output_defined_context *ctx;
208 struct stmt_defines_port_output_context s_ctx;
210 port = (struct port *)data;
211 ctx = (struct port_output_defined_context *)context;
213 if (port->type == port_type_input)
214 return;
216 s_ctx.filename = ctx->filename;
217 s_ctx.locp = ctx->locp;
218 s_ctx.port = port;
219 s_ctx.defined = 0;
220 list_for_each(ctx->stmts, stmt_defines_port_output, &s_ctx);
222 if (!s_ctx.defined)
223 {
224 fprintf(stderr, "%s:%d:%d: error: the output of port `%s' was "
225 "not defined\n", ctx->filename, ctx->locp->first_line,
226 ctx->locp->first_column, port->id);
227 exit(EXIT_FAILURE);
228 }
229 }
231 struct stmt_bind_context
232 {
233 const char *filename;
234 YYLTYPE *locp;
235 list_t ports;
236 };
238 static void
239 stmt_bind(void *data, void *context)
240 {
241 struct stmt *stmt;
242 struct stmt_bind_context *ctx;
243 struct port *port;
244 struct expr_signal_id *id;
245 struct ext_func *f;
246 char *s;
248 stmt = (struct stmt *)data;
249 ctx = (struct stmt_bind_context *)context;
251 port = list_find(ctx->ports, port_cmp_id, stmt->out.id.id);
252 if (port == NULL)
253 {
254 fprintf(stderr, "%s:%d:%d: error: unknown port `%s'\n",
255 ctx->filename, ctx->locp->first_line,
256 ctx->locp->first_column, stmt->out.id.id);
257 exit(EXIT_FAILURE);
258 }
260 if (stmt->out.id.out && (port->type != port_type_w)
261 && (port->type != port_type_k))
262 {
263 fprintf(stderr, "%s:%d:%d: error: port `%s' is not a physical "
264 "port\n", ctx->filename, ctx->locp->first_line,
265 ctx->locp->first_column, stmt->out.id.id);
266 exit(EXIT_FAILURE);
267 }
268 else if (!stmt->out.id.out && (port->type != port_type_input)
269 && (port->type != port_type_output))
270 {
271 fprintf(stderr, "%s:%d:%d: error: port `%s' is a physical "
272 "port\n", ctx->filename, ctx->locp->first_line,
273 ctx->locp->first_column, stmt->out.id.id);
274 exit(EXIT_FAILURE);
275 }
277 stmt->out.port = port;
279 id = expr_bind_to_ports(stmt->expr, ctx->ports);
280 if (id != NULL)
281 {
282 if (id->in)
283 fprintf(stderr, "%s:%d:%d: error: port `%s' is not a "
284 "physical port\n", ctx->filename,
285 ctx->locp->first_line, ctx->locp->first_column,
286 id->id);
287 else
288 fprintf(stderr, "%s:%d:%d: error: port `%s' is a "
289 "physical port\n", ctx->filename,
290 ctx->locp->first_line, ctx->locp->first_column,
291 id->id);
292 exit(EXIT_FAILURE);
293 }
295 expr_bind_consts(stmt->expr, parser_consts);
297 id = expr_find_unbinded(stmt->expr);
298 if (id != NULL)
299 {
300 fprintf(stderr, "%s:%d:%d: error: unknown port `%s'\n",
301 ctx->filename, ctx->locp->first_line,
302 ctx->locp->first_column, id->id);
303 exit(EXIT_FAILURE);
304 }
306 s = expr_bind_ext_funcs(stmt->expr, parser_ext_funcs);
307 if (s != NULL)
308 {
309 fprintf(stderr, "%s:%d:%d: error: unknown function `%s'\n",
310 ctx->filename, ctx->locp->first_line,
311 ctx->locp->first_column, s);
312 exit(EXIT_FAILURE);
313 }
315 f = expr_check_ext_func_args(stmt->expr);
316 if (f != NULL)
317 {
318 fprintf(stderr, "%s:%d:%d: error: function `%s' takes %lu "
319 "arguments\n", ctx->filename, ctx->locp->first_line,
320 ctx->locp->first_column, f->id, f->n_args);
321 exit(EXIT_FAILURE);
322 }
323 }
325 struct component_bind_type_context
326 {
327 const char *filename;
328 YYLTYPE *locp;
329 };
331 static void
332 component_bind_type(void *data, void *context)
333 {
334 struct component *comp;
335 struct component_bind_type_context *ctx;
336 void *p;
338 comp = (struct component *)data;
339 ctx = (struct component_bind_type_context *)context;
341 p = list_find(parser_blocks, block_cmp_id, comp->type.id);
342 if (p != NULL)
343 {
344 free(comp->type.id);
345 comp->type.t.is_macro = 0;
346 comp->type.t.p = p;
347 return;
348 }
350 p = list_find(parser_macros, system_cmp_id, comp->type.id);
351 if (p != NULL)
352 {
353 free(comp->type.id);
354 comp->type.t.is_macro = 1;
355 comp->type.t.p = p;
356 return;
357 }
359 fprintf(stderr, "%s:%d:%d: error: unknown component type `%s'\n",
360 ctx->filename, ctx->locp->first_line, ctx->locp->first_column,
361 comp->type.id);
362 exit(EXIT_FAILURE);
363 }
365 static void
366 conn_elem_bind(struct conn_elem *elem, list_t components, list_t ports,
367 const char *filename, YYLTYPE *locp)
368 {
369 struct component *comp;
370 struct port *port;
371 struct const_v *const_v;
373 if (elem->type == conn_elem_type_value)
374 return;
376 if (elem->c.id.component != NULL)
377 {
378 comp = list_find(components, component_cmp_id,
379 elem->c.id.component);
380 if (comp == NULL)
381 {
382 fprintf(stderr, "%s:%d:%d: error: unknown component "
383 "`%s'\n", filename, locp->first_line,
384 locp->first_column, elem->c.id.component);
385 exit(EXIT_FAILURE);
386 }
388 port = list_find(comp->type.t.is_macro
389 ? ((struct system *)comp->type.t.p)->ports
390 : ((struct block *)comp->type.t.p)->ports,
391 port_cmp_id, elem->c.id.port);
392 if (port == NULL)
393 {
394 fprintf(stderr, "%s:%d:%d: error: component `%s' does "
395 "not have a port named `%s'\n", filename,
396 locp->first_line, locp->first_column,
397 elem->c.id.component, elem->c.id.port);
398 exit(EXIT_FAILURE);
399 }
401 free(elem->c.id.component);
402 free(elem->c.id.port);
403 elem->c.p.component = comp;
404 elem->c.p.port = port;
405 }
406 else
407 {
408 port = list_find(ports, port_cmp_id, elem->c.id.port);
409 if (port == NULL)
410 {
411 const_v = list_find(parser_consts, const_cmp_id,
412 elem->c.id.port);
413 if (const_v == NULL)
414 {
415 fprintf(stderr, "%s:%d:%d: error: unknown port "
416 "`%s'\n", filename, locp->first_line,
417 locp->first_column, elem->c.id.port);
418 exit(EXIT_FAILURE);
419 }
421 free(elem->c.id.port);
422 elem->c.value = const_v->value;
423 elem->type = conn_elem_type_value;
424 return;
425 }
427 free(elem->c.id.port);
428 elem->c.p.component = NULL;
429 elem->c.p.port = port;
430 }
432 if ((elem->type != conn_elem_type_port)
433 && (elem->c.p.port->type != port_type_w)
434 && (elem->c.p.port->type != port_type_k))
435 {
436 fprintf(stderr, "%s:%d:%d: error: port `%s%s%s' is not a "
437 "physical port\n", filename, locp->first_line,
438 locp->first_column,
439 (elem->c.p.component != NULL) ? elem->c.p.component->id
440 : "", (elem->c.p.component != NULL) ? "." : "",
441 elem->c.p.port->id);
442 exit(EXIT_FAILURE);
443 }
444 }
446 struct connection_bind_context
447 {
448 const char *filename;
449 YYLTYPE *locp;
450 list_t ports;
451 list_t components;
452 };
454 #define CONN_ELEM_IS_W(elem) \
455 (((elem).type == conn_elem_type_port) \
456 && ((elem).c.p.port->type == port_type_w))
458 #define CONN_ELEM_IS_K(elem) \
459 (((elem).type == conn_elem_type_port) \
460 && ((elem).c.p.port->type == port_type_k))
462 #define CONN_ELEM_IS_PHYS(elem) (CONN_ELEM_IS_W(elem) || CONN_ELEM_IS_K(elem))
464 static void
465 connection_bind(void *data, void *context)
466 {
467 struct connection *conn;
468 struct connection_bind_context *ctx;
470 conn = (struct connection *)data;
471 ctx = (struct connection_bind_context *)context;
473 conn_elem_bind(&conn->output, ctx->components, ctx->ports,
474 ctx->filename, ctx->locp);
476 if (((conn->output.c.p.component == NULL)
477 && (conn->output.c.p.port->type == port_type_input))
478 || ((conn->output.c.p.component != NULL)
479 && (conn->output.c.p.port->type == port_type_output)))
480 {
481 fprintf(stderr, "%s:%d:%d: error: invalid connection\n",
482 ctx->filename, ctx->locp->first_line,
483 ctx->locp->first_column);
484 exit(EXIT_FAILURE);
485 }
487 if (conn->input.type == conn_elem_type_value)
488 {
489 if (CONN_ELEM_IS_PHYS(conn->output))
490 {
491 fprintf(stderr, "%s:%d:%d: error: cannot assign a "
492 "value to a physical port\n", ctx->filename,
493 ctx->locp->first_line, ctx->locp->first_column);
494 exit(EXIT_FAILURE);
495 }
496 return;
497 }
499 conn_elem_bind(&conn->input, ctx->components, ctx->ports, ctx->filename,
500 ctx->locp);
502 if (conn->input.type == conn_elem_type_value)
503 {
504 if (CONN_ELEM_IS_PHYS(conn->output))
505 {
506 fprintf(stderr, "%s:%d:%d: error: cannot assign a "
507 "value to a physical port\n", ctx->filename,
508 ctx->locp->first_line, ctx->locp->first_column);
509 exit(EXIT_FAILURE);
510 }
511 return;
512 }
514 if (((conn->input.c.p.component != NULL)
515 && (conn->input.c.p.port->type == port_type_input))
516 || ((conn->input.c.p.component == NULL)
517 && (conn->input.c.p.port->type == port_type_output))
518 || (CONN_ELEM_IS_W(conn->input) && !CONN_ELEM_IS_W(conn->output))
519 || (!CONN_ELEM_IS_W(conn->input) && CONN_ELEM_IS_W(conn->output))
520 || (CONN_ELEM_IS_K(conn->input) && !CONN_ELEM_IS_K(conn->output))
521 || (!CONN_ELEM_IS_K(conn->input) && CONN_ELEM_IS_K(conn->output)))
522 {
523 fprintf(stderr, "%s:%d:%d: error: invalid connection\n",
524 ctx->filename, ctx->locp->first_line,
525 ctx->locp->first_column);
526 exit(EXIT_FAILURE);
527 }
529 if (conn->input.c.p.port == conn->output.c.p.port)
530 {
531 fprintf(stderr, "%s:%d:%d: error: self connection\n",
532 ctx->filename, ctx->locp->first_line,
533 ctx->locp->first_column);
534 exit(EXIT_FAILURE);
535 }
536 }
538 struct connection_defines_port_context
539 {
540 const char *filename;
541 YYLTYPE *locp;
542 struct component *comp;
543 struct port *port;
544 char defined;
545 };
547 static void
548 connection_defines_port(void *data, void *context)
549 {
550 struct connection *conn;
551 struct connection_defines_port_context *ctx;
552 char defined;
554 conn = (struct connection *)data;
555 ctx = (struct connection_defines_port_context *)context;
557 defined = ((conn->output.c.p.port == ctx->port)
558 && (conn->output.c.p.component == ctx->comp));
559 if (((ctx->port->type == port_type_w)
560 || (ctx->port->type == port_type_k))
561 && (conn->input.type == conn_elem_type_port))
562 defined = defined
563 || ((conn->input.c.p.port == ctx->port)
564 && (conn->input.c.p.component == ctx->comp));
566 if (!defined)
567 return;
569 if (ctx->defined)
570 {
571 fprintf(stderr, "%s:%d:%d: error: port `%s%s%s' is connected "
572 "more than once\n", ctx->filename,
573 ctx->locp->first_line, ctx->locp->first_column,
574 (ctx->comp != NULL) ? ctx->comp->id : "",
575 (ctx->comp != NULL) ? "." : "", ctx->port->id);
576 exit(EXIT_FAILURE);
577 }
579 ctx->defined = 1;
580 }
582 struct output_port_defined_context
583 {
584 const char *filename;
585 YYLTYPE *locp;
586 list_t connections;
587 };
589 static void
590 output_port_defined(void *data, void *context)
591 {
592 struct port *port;
593 struct output_port_defined_context *ctx;
594 struct connection_defines_port_context c_ctx;
596 port = (struct port *)data;
597 ctx = (struct output_port_defined_context *)context;
599 if (port->type == port_type_input)
600 return;
602 c_ctx.filename = ctx->filename;
603 c_ctx.locp = ctx->locp;
604 c_ctx.comp = NULL;
605 c_ctx.port = port;
606 c_ctx.defined = 0;
607 list_for_each(ctx->connections, connection_defines_port, &c_ctx);
609 if (!c_ctx.defined)
610 {
611 fprintf(stderr, "%s:%d:%d: error: the output of port `%s' was "
612 "not defined\n", ctx->filename, ctx->locp->first_line,
613 ctx->locp->first_column, port->id);
614 exit(EXIT_FAILURE);
615 }
616 }
618 struct component_single_conn_context
619 {
620 const char *filename;
621 YYLTYPE *locp;
622 struct component *comp;
623 list_t connections;
624 };
626 static void
627 port_single_conn(void *data, void *context)
628 {
629 struct port *port;
630 struct component_single_conn_context *ctx;
631 struct connection_defines_port_context c_ctx;
633 port = (struct port *)data;
634 ctx = (struct component_single_conn_context *)context;
636 if (port->type == port_type_output)
637 return;
639 c_ctx.filename = ctx->filename;
640 c_ctx.locp = ctx->locp;
641 c_ctx.comp = ctx->comp;
642 c_ctx.port = port;
643 c_ctx.defined = 0;
644 list_for_each(ctx->connections, connection_defines_port, &c_ctx);
645 }
647 static void
648 component_single_conn(void *data, void *context)
649 {
650 struct component *comp;
651 struct component_single_conn_context *ctx;
653 comp = (struct component *)data;
654 ctx = (struct component_single_conn_context *)context;
656 ctx->comp = comp;
658 list_for_each(comp->type.t.is_macro
659 ? ((struct system *)comp->type.t.p)->ports
660 : ((struct block *)comp->type.t.p)->ports,
661 port_single_conn, ctx);
662 }
664 static void
665 system_bind(struct system *system, list_t ports, list_t components,
666 list_t connections, const char *filename, YYLTYPE *locp)
667 {
668 struct component *comp;
669 struct component_bind_type_context c_ctx;
670 struct connection_bind_context cb_ctx;
671 struct output_port_defined_context o_ctx;
672 struct component_single_conn_context s_ctx;
674 system->ports = ports;
675 system->components = components;
676 system->connections = connections;
678 /* ports and components to have different ids */
679 comp = list_find(components, component_cmp_ports_id, ports);
680 if (comp != NULL)
681 {
682 fprintf(stderr, "%s:%d:%d: error: id `%s' was already used for "
683 "a port\n", filename, locp->first_line,
684 locp->first_column, comp->id);
685 exit(EXIT_FAILURE);
686 }
688 /* bind component types */
689 c_ctx.filename = filename;
690 c_ctx.locp = locp;
691 list_for_each(components, component_bind_type, &c_ctx);
693 /* bind connections */
694 cb_ctx.filename = filename;
695 cb_ctx.locp = locp;
696 cb_ctx.ports = ports;
697 cb_ctx.components = components;
698 list_for_each(connections, connection_bind, &cb_ctx);
700 /* all external outputs/external physical ports defined (once) */
701 o_ctx.filename = filename;
702 o_ctx.locp = locp;
703 o_ctx.connections = connections;
704 list_for_each(ports, output_port_defined, &o_ctx);
706 /* 1 connection per internal input/physical port */
707 s_ctx.filename = filename;
708 s_ctx.locp = locp;
709 s_ctx.comp = NULL;
710 s_ctx.connections = connections;
711 list_for_each(components, component_single_conn, &s_ctx);
712 }
714 %}
716 %union {
717 unsigned long l;
718 double val;
719 char *str;
720 list_t list;
721 struct const_v const_v;
722 struct ext_func ext_func;
723 struct block block;
724 struct system system;
725 struct stmt stmt;
726 expr_t expr;
727 struct component component;
728 struct connection connection;
729 struct conn_elem conn_elem;
730 struct port port;
731 enum port_type port_type;
732 enum port_sync port_sync;
733 }
735 %token IMPORT CONST EXT_FUNCTION BLOCK MACRO SYSTEM SYNC ASYNC INPUT
736 OUTPUT W_PORT K_PORT IN OUT SAMPLE_RATE SEMICOLON LBRACE RBRACE
737 DOT COMA EQUALS LPAR RPAR LSBRACKET RSBRACKET
738 %token <str> ID STRING
739 %token <l> INTEGER
740 %token <val> FLOAT
742 %left PLUS MINUS
743 %left ASTERISK SLASH
744 %left NEG POS
746 %type <const_v> const
747 %type <ext_func> ext_func
748 %type <block> block
749 %type <block> block_code
750 %type <list> stmts
751 %type <stmt> stmt
752 %type <expr> expr
753 %type <list> expr_list
754 %type <system> macro
755 %type <system> macro_code
756 %type <system> system
757 %type <system> system_code
758 %type <list> components
759 %type <component> component
760 %type <list> connections
761 %type <connection> connection
762 %type <conn_elem> conn_elem
763 %type <val> sign_value
764 %type <list> ports
765 %type <port> port
766 %type <port_type> port_type
767 %type <list> sys_ports
768 %type <port> sys_port
769 %type <port_sync> sys_port_sync
770 %type <val> value
772 %defines "src/parser.tab.h"
773 %output "src/parser.tab.c"
775 %define api.pure
776 %locations
777 %parse-param {yyscan_t yyscanner}
778 %parse-param {const char *filename}
779 %lex-param {yyscan_t yyscanner}
781 %%
783 file: imports defs;
785 imports: /* empty */
786 | imports import;
788 import: IMPORT ID SEMICOLON { parser_import($2); }
789 ;
791 defs: /* empty */
792 | defs const
793 {
794 if (list_find(parser_consts, const_cmp_id, $2.id)
795 != NULL)
796 {
797 fprintf(stderr, "%s:%d:%d: error: a constant "
798 "with id `%s' was already defined\n",
799 filename, @2.first_line,
800 @2.first_column, $2.id);
801 exit(EXIT_FAILURE);
802 }
803 list_append_copy(parser_consts, &$2, sizeof($2));
804 }
805 | defs ext_func
806 {
807 if (list_find(parser_ext_funcs, ext_func_cmp_id, $2.id)
808 != NULL)
809 {
810 fprintf(stderr, "%s:%d:%d: error: a function "
811 "with id `%s' was already defined\n",
812 filename, @2.first_line,
813 @2.first_column, $2.id);
814 exit(EXIT_FAILURE);
815 }
816 list_append_copy(parser_ext_funcs, &$2, sizeof($2));
817 }
818 | defs block
819 {
820 if (list_find(parser_blocks, block_cmp_id, $2.id)
821 != NULL)
822 {
823 fprintf(stderr, "%s:%d:%d: error: a block with "
824 "id `%s' was already defined\n",
825 filename, @2.first_line,
826 @2.first_column, $2.id);
827 exit(EXIT_FAILURE);
828 }
829 list_append_copy(parser_blocks, &$2, sizeof($2));
830 }
831 | defs macro
832 {
833 if (list_find(parser_macros, system_cmp_id, $2.id)
834 != NULL)
835 {
836 fprintf(stderr, "%s:%d:%d: error: a macro with "
837 "id `%s' was already defined\n",
838 filename, @2.first_line,
839 @2.first_column, $2.id);
840 exit(EXIT_FAILURE);
841 }
842 list_append_copy(parser_macros, &$2, sizeof($2));
843 }
844 | defs system
845 {
846 if (list_find(parser_systems, system_cmp_id, $2.id)
847 != NULL)
848 {
849 fprintf(stderr, "%s:%d:%d: error: a system "
850 "with id `%s' was already defined\n",
851 filename, @2.first_line,
852 @2.first_column, $2.id);
853 exit(EXIT_FAILURE);
854 }
855 list_append_copy(parser_systems, &$2, sizeof($2));
856 }
857 ;
859 const: CONST ID EQUALS sign_value SEMICOLON
860 {
861 $$.id = $2;
862 $$.value = $4;
863 }
864 ;
866 ext_func: EXT_FUNCTION ID EQUALS ID COMA ID COMA INTEGER COMA STRING COMA
867 STRING SEMICOLON
868 {
869 if ($8 == 0)
870 {
871 fprintf(stderr, "%s:%d:%d: error: function "
872 "`%s' must take at least one "
873 "argument\n", filename, @2.first_line,
874 @2.first_column, $2);
875 exit(EXIT_FAILURE);
876 }
878 $$.id = $2;
879 $$.f_id = $4;
880 $$.d_id = $6;
881 $$.n_args = $8;
882 $$.include = $10;
883 $$.lib = $12;
884 }
885 ;
887 block: BLOCK ID LBRACE block_code RBRACE
888 {
889 $$ = $4;
890 $$.id = $2;
891 }
892 ;
894 block_code: ports stmts
895 {
896 struct port_output_defined_context p_ctx;
897 struct stmt_bind_context s_ctx;
899 /* all output ports defined */
900 p_ctx.filename = filename;
901 p_ctx.locp = &(@1);
902 p_ctx.stmts = $2;
903 list_for_each($1, port_output_defined, &p_ctx);
905 /* bind statements */
906 s_ctx.filename = filename;
907 s_ctx.locp = &(@1);
908 s_ctx.ports = $1;
909 list_for_each($2, stmt_bind, &s_ctx);
911 $$.id = NULL;
912 $$.ports = $1;
913 $$.stmts = $2;
914 }
915 ;
917 stmts: stmt
918 {
919 $$ = list_new();
920 list_append_copy($$, &($1), sizeof($1));
921 }
922 | stmts stmt
923 {
924 if (list_find($1, stmt_cmp_output, &$2) != NULL)
925 {
926 fprintf(stderr, "%s:%d:%d: error: double "
927 "statement for `%s%s'\n",
928 filename, @1.first_line,
929 @1.first_column, $2.out.id.id,
930 $2.out.id.out ? ".out" : "");
931 exit(EXIT_FAILURE);
932 }
933 $$ = $1;
934 list_append_copy($$, &($2), sizeof($2));
935 }
936 ;
938 stmt: ID EQUALS expr SEMICOLON
939 {
940 $$.out.id.id = $1;
941 $$.out.id.out = 0;
942 $$.expr = $3;
943 }
944 | ID DOT OUT EQUALS expr SEMICOLON
945 {
946 $$.out.id.id = $1;
947 $$.out.id.out = 1;
948 $$.expr = $5;
949 }
950 ;
952 expr: value
953 {
954 $$ = expr_new_value($1);
955 }
956 | SAMPLE_RATE
957 {
958 $$ = expr_new_sample_rate();
959 }
960 | ID
961 {
962 $$ = expr_new_signal($1, 0, NULL, NULL);
963 }
964 | ID DOT IN
965 {
966 $$ = expr_new_signal($1, 1, NULL, NULL);
967 }
968 | ID LSBRACKET expr RSBRACKET
969 {
970 $$ = expr_new_signal($1, 0, $3, NULL);
971 }
972 | ID DOT IN LSBRACKET expr RSBRACKET
973 {
974 $$ = expr_new_signal($1, 1, $5, NULL);
975 }
976 | ID LSBRACKET expr COMA expr RSBRACKET
977 {
978 $$ = expr_new_signal($1, 0, $3, $5);
979 }
980 | ID DOT IN LSBRACKET expr COMA expr RSBRACKET
981 {
982 $$ = expr_new_signal($1, 1, $5, $7);
983 }
984 | ID LPAR expr_list RPAR
985 {
986 $$ = expr_new_call($1, $3);
987 }
988 | expr PLUS expr
989 {
990 expr_push_add($1, $3);
991 $$ = $1;
992 }
993 | expr MINUS expr
994 {
995 expr_push_sub($1, $3);
996 $$ = $1;
997 }
998 | expr ASTERISK expr
999 {
1000 expr_push_mul($1, $3);
1001 $$ = $1;
1003 | expr SLASH expr
1005 expr_push_div($1, $3);
1006 $$ = $1;
1008 | PLUS expr %prec POS
1010 if (expr_top_is_sign($2))
1012 fprintf(stderr, "%s:%d:%d: error: multiple "
1013 "sign operators in expression\n",
1014 filename, @1.first_line,
1015 @1.first_column);
1016 exit(EXIT_FAILURE);
1018 expr_push_plus($2);
1019 $$ = $2;
1021 | MINUS expr %prec NEG
1023 if (expr_top_is_sign($2))
1025 fprintf(stderr, "%s:%d:%d: error: multiple "
1026 "sign operators in expression\n",
1027 filename, @1.first_line,
1028 @1.first_column);
1029 exit(EXIT_FAILURE);
1031 expr_push_minus($2);
1032 $$ = $2;
1034 | LPAR expr RPAR
1036 $$ = $2;
1040 expr_list: expr
1042 $$ = list_new();
1043 list_append($$, $1);
1045 | expr_list COMA expr
1047 $$ = $1;
1048 list_append($$, $3);
1052 macro: MACRO ID LBRACE macro_code RBRACE
1054 $$ = $4;
1055 $$.id = $2;
1059 macro_code: ports components connections
1061 $$.id = NULL;
1062 system_bind(&$$, $1, $2, $3, filename, &(@1));
1066 system: SYSTEM ID LBRACE system_code RBRACE
1068 $$ = $4;
1069 $$.id = $2;
1073 system_code: sys_ports components connections
1075 $$.id = NULL;
1076 system_bind(&$$, $1, $2, $3, filename, &(@1));
1080 components: /* empty */
1082 $$ = list_new();
1084 | components component
1086 if (list_find($1, component_cmp_id, $2.id) != NULL)
1088 fprintf(stderr, "%s:%d:%d: error: a component "
1089 "with id `%s' was already specified\n",
1090 filename, @2.first_line,
1091 @2.first_column, $2.id);
1092 exit(EXIT_FAILURE);
1094 $$ = $1;
1095 list_append_copy($$, &($2), sizeof($2));
1099 component: ID ID SEMICOLON
1101 $$.type.id = $1;
1102 $$.id = $2;
1106 connections: connection
1108 $$ = list_new();
1109 list_append_copy($$, &($1), sizeof($1));
1111 | connections connection
1113 if (list_find($1, connection_cmp, &$2) != NULL)
1115 fprintf(stderr, "%s:%d:%d: error: connection "
1116 "already specified\n", filename,
1117 @2.first_line, @2.first_column);
1118 exit(EXIT_FAILURE);
1120 $$ = $1;
1121 list_append_copy($$, &($2), sizeof($2));
1125 connection: conn_elem EQUALS conn_elem SEMICOLON
1127 if ((($1.c.id.component == NULL)
1128 && ($1.type == conn_elem_type_in))
1129 || (($1.c.id.component != NULL)
1130 && ($1.type == conn_elem_type_out))
1131 || (($3.c.id.component == NULL)
1132 && ($3.type == conn_elem_type_out))
1133 || (($3.c.id.component != NULL)
1134 && ($3.type == conn_elem_type_in))
1135 || ($1.type == conn_elem_type_value)
1136 || (($3.type == conn_elem_type_value)
1137 && ((($1.c.id.component == NULL)
1138 && ($1.type == conn_elem_type_in))
1139 || (($1.c.id.component != NULL)
1140 && ($1.type == conn_elem_type_out)))))
1142 fprintf(stderr, "%s:%d:%d: error: invalid "
1143 "connection\n", filename, @1.first_line,
1144 @1.first_column);
1145 exit(EXIT_FAILURE);
1147 $$.output = $1;
1148 $$.input = $3;
1152 conn_elem: ID
1154 $$.type = conn_elem_type_port;
1155 $$.c.id.component = NULL;
1156 $$.c.id.port = $1;
1158 | ID DOT IN
1160 $$.type = conn_elem_type_in;
1161 $$.c.id.component = NULL;
1162 $$.c.id.port = $1;
1164 | ID DOT OUT
1166 $$.type = conn_elem_type_out;
1167 $$.c.id.component = NULL;
1168 $$.c.id.port = $1;
1170 | ID DOT ID
1172 $$.type = conn_elem_type_port;
1173 $$.c.id.component = $1;
1174 $$.c.id.port = $3;
1176 | ID DOT ID DOT IN
1178 $$.type = conn_elem_type_in;
1179 $$.c.id.component = $1;
1180 $$.c.id.port = $3;
1182 | ID DOT ID DOT OUT
1184 $$.type = conn_elem_type_out;
1185 $$.c.id.component = $1;
1186 $$.c.id.port = $3;
1188 | sign_value
1190 $$.type = conn_elem_type_value;
1191 $$.c.value = $1;
1195 ports: port
1197 $$ = list_new();
1198 list_append_copy($$, &($1), sizeof($1));
1200 | ports port
1202 if (list_find($1, port_cmp_id, $2.id) != NULL)
1204 fprintf(stderr, "%s:%d:%d: error: a port with "
1205 "id `%s' was already defined\n",
1206 filename, @2.first_line,
1207 @2.first_column, $2.id);
1208 exit(EXIT_FAILURE);
1210 $$ = $1;
1211 list_append_copy($$, &($2), sizeof($2));
1215 port: port_type ID SEMICOLON
1217 $$.sync = port_sync_unknown;
1218 $$.type = $1;
1219 $$.id = $2;
1223 sys_ports: sys_port
1225 $$ = list_new();
1226 list_append_copy($$, &($1), sizeof($1));
1228 | sys_ports sys_port
1230 if (list_find($1, port_cmp_id, $2.id) != NULL)
1232 fprintf(stderr, "%s:%d:%d: error: a port with "
1233 "id `%s' was already defined\n",
1234 filename, @2.first_line,
1235 @2.first_column, $2.id);
1236 exit(EXIT_FAILURE);
1238 $$ = $1;
1239 list_append_copy($$, &($2), sizeof($2));
1243 sys_port: sys_port_sync port_type ID SEMICOLON
1245 if (($2 == port_type_w) || ($2 == port_type_k))
1247 fprintf(stderr, "%s:%d:%d: error: systems "
1248 "cannot expose physical ports\n",
1249 filename, @2.first_line,
1250 @2.first_column);
1251 exit(EXIT_FAILURE);
1253 $$.sync = $1;
1254 $$.type = $2;
1255 $$.id = $3;
1259 sys_port_sync: SYNC { $$ = port_sync_sync; }
1260 | ASYNC { $$ = port_sync_async; }
1263 port_type: INPUT { $$ = port_type_input; }
1264 | OUTPUT { $$ = port_type_output; }
1265 | W_PORT { $$ = port_type_w; }
1266 | K_PORT { $$ = port_type_k; }
1269 sign_value: value { $$ = $1; }
1270 | PLUS value { $$ = $2; }
1271 | MINUS value { $$ = -$2; }
1274 value: INTEGER { $$ = (double)$1; }
1275 | FLOAT { $$ = $1; }