source: mainline/uspace/app/bithenge/script.c@ 3c70376

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 3c70376 was 3c70376, checked in by Sean Bartell <wingedtachikoma@…>, 13 years ago

Bithenge: move compound transforms to separate file; fix warnings

  • Property mode set to 100644
File size: 28.7 KB
Line 
1/*
2 * Copyright (c) 2012 Sean Bartell
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup bithenge
30 * @{
31 */
32/**
33 * @file
34 * Script parsing.
35 */
36
37#include <ctype.h>
38#include <stdio.h>
39#include <stdlib.h>
40#include "compound.h"
41#include "expression.h"
42#include "os.h"
43#include "script.h"
44#include "sequence.h"
45#include "transform.h"
46#include "tree.h"
47
48/** Tokens with more characters than this may be read incorrectly. */
49#define MAX_TOKEN_SIZE 256
50#define BUFFER_SIZE 4096
51
52/** Single-character symbols are represented by the character itself. Every
53 * other token uses one of these values: */
54typedef enum {
55 TOKEN_EQUALS = -128,
56 TOKEN_ERROR,
57 TOKEN_EOF,
58 TOKEN_IDENTIFIER,
59 TOKEN_INTEGER,
60 TOKEN_LEFT_ARROW,
61
62 /* Keywords */
63 TOKEN_DO,
64 TOKEN_ELSE,
65 TOKEN_FALSE,
66 TOKEN_IF,
67 TOKEN_IN,
68 TOKEN_REPEAT,
69 TOKEN_STRUCT,
70 TOKEN_SWITCH,
71 TOKEN_TRANSFORM,
72 TOKEN_TRUE,
73 TOKEN_WHILE,
74} token_type_t;
75
76/** Singly-linked list of named transforms. */
77typedef struct transform_list {
78 char *name;
79 bithenge_transform_t *transform;
80 struct transform_list *next;
81} transform_list_t;
82
83/** State kept by the parser. */
84typedef struct {
85 /** Rather than constantly checking return values, the parser uses this
86 * to indicate whether an error has occurred. */
87 int error;
88
89 /** The list of named transforms. */
90 transform_list_t *transform_list;
91
92 /** The name of the script file. */
93 const char *filename;
94 /** The script file being read from. */
95 FILE *file;
96 /** The buffer that holds script code. There is always a '\0' after the
97 * current position to prevent reading too far. */
98 char buffer[BUFFER_SIZE];
99 /** The start position within the buffer of the next unread token. */
100 size_t buffer_pos;
101 /** The start position within the buffer of the current token. */
102 size_t old_buffer_pos;
103 /** The line number of the current token. */
104 int lineno;
105 /** Added to a buffer position to find the column number. */
106 int line_offset;
107
108 /** The type of the current token. */
109 token_type_t token;
110 union {
111 /** The value of a TOKEN_IDENTIFIER token. Unless changed to
112 * NULL, it will be freed when the next token is read. */
113 char *token_string;
114 /** The value of a TOKEN_INTEGER token. */
115 bithenge_int_t token_int;
116 };
117
118 /** The names of the current transform's parameters. */
119 char **parameter_names;
120 /** The number of parameters. */
121 int num_params;
122 /** @a parse_expression sets this when TOKEN_IN is used. */
123 bool in_node_used;
124} state_t;
125
126/** Free the previous token's data. This must be called before changing
127 * state->token. */
128static void done_with_token(state_t *state)
129{
130 if (state->token == TOKEN_IDENTIFIER)
131 free(state->token_string);
132 state->token = TOKEN_ERROR;
133}
134
135/** Note that an error has occurred if error is not EOK. */
136static void error_errno(state_t *state, int error)
137{
138 // Don't overwrite a previous error.
139 if (state->error == EOK && error != EOK) {
140 done_with_token(state);
141 state->token = TOKEN_ERROR;
142 state->error = error;
143 }
144}
145
146/** Note that a syntax error has occurred and print an error message. */
147static void syntax_error(state_t *state, const char *message)
148{
149 // Printing multiple errors is confusing.
150 if (state->error == EOK) {
151 size_t start_char = state->old_buffer_pos + state->line_offset;
152 size_t end_char = state->buffer_pos + state->line_offset;
153 size_t size = end_char - start_char;
154 fprintf(stderr, "%s:%d:", state->filename, state->lineno);
155 if (size <= 1)
156 fprintf(stderr, "%zd: ", start_char);
157 else
158 fprintf(stderr, "%zd-%zd: ", start_char, end_char - 1);
159 fprintf(stderr, "%s: \"%.*s\"\n", message, (int)size,
160 state->buffer + state->old_buffer_pos);
161 error_errno(state, EINVAL);
162 }
163}
164
165/** Ensure the buffer contains enough characters to read a token. */
166static void fill_buffer(state_t *state)
167{
168 if (state->buffer_pos + MAX_TOKEN_SIZE < BUFFER_SIZE)
169 return;
170
171 size_t empty_size = state->buffer_pos;
172 size_t used_size = BUFFER_SIZE - 1 - state->buffer_pos;
173 memmove(state->buffer, state->buffer + state->buffer_pos, used_size);
174 state->line_offset += state->buffer_pos;
175 state->buffer_pos = 0;
176
177 size_t read_size = fread(state->buffer + used_size, 1, empty_size,
178 state->file);
179 if (ferror(state->file))
180 error_errno(state, EIO);
181 state->buffer[used_size + read_size] = '\0';
182}
183
184/** Read the next token. */
185static void next_token(state_t *state)
186{
187 fill_buffer(state);
188 done_with_token(state);
189 state->old_buffer_pos = state->buffer_pos;
190 char ch = state->buffer[state->buffer_pos];
191 if (ch == '\0') {
192 state->token = TOKEN_EOF;
193 } else if (ch == '#') {
194 while (state->buffer[state->buffer_pos] != '\n'
195 && state->buffer[state->buffer_pos] != '\0') {
196 state->buffer_pos++;
197 fill_buffer(state);
198 }
199 next_token(state);
200 return;
201 } else if (isspace(ch)) {
202 // Will eventually reach the '\0' at the end
203 while (isspace(state->buffer[state->buffer_pos])) {
204 if (state->buffer[state->buffer_pos] == '\n') {
205 state->lineno++;
206 state->line_offset = -state->buffer_pos;
207 }
208 state->buffer_pos++;
209 }
210 next_token(state);
211 return;
212 } else if (isalpha(ch)) {
213 while (isalnum(state->buffer[state->buffer_pos])
214 || state->buffer[state->buffer_pos] == '_')
215 state->buffer_pos++;
216 char *value = str_ndup(state->buffer + state->old_buffer_pos,
217 state->buffer_pos - state->old_buffer_pos);
218 if (!value) {
219 error_errno(state, ENOMEM);
220 } else if (!str_cmp(value, "do")) {
221 state->token = TOKEN_DO;
222 free(value);
223 } else if (!str_cmp(value, "else")) {
224 state->token = TOKEN_ELSE;
225 free(value);
226 } else if (!str_cmp(value, "false")) {
227 state->token = TOKEN_FALSE;
228 free(value);
229 } else if (!str_cmp(value, "if")) {
230 state->token = TOKEN_IF;
231 free(value);
232 } else if (!str_cmp(value, "in")) {
233 state->token = TOKEN_IN;
234 free(value);
235 } else if (!str_cmp(value, "repeat")) {
236 state->token = TOKEN_REPEAT;
237 free(value);
238 } else if (!str_cmp(value, "struct")) {
239 state->token = TOKEN_STRUCT;
240 free(value);
241 } else if (!str_cmp(value, "switch")) {
242 state->token = TOKEN_SWITCH;
243 free(value);
244 } else if (!str_cmp(value, "transform")) {
245 state->token = TOKEN_TRANSFORM;
246 free(value);
247 } else if (!str_cmp(value, "true")) {
248 state->token = TOKEN_TRUE;
249 free(value);
250 } else if (!str_cmp(value, "while")) {
251 state->token = TOKEN_WHILE;
252 free(value);
253 } else {
254 state->token = TOKEN_IDENTIFIER;
255 state->token_string = value;
256 }
257 } else if (isdigit(ch)) {
258 while (isdigit(state->buffer[state->buffer_pos]))
259 state->buffer_pos++;
260 state->token = TOKEN_INTEGER;
261 int rc = bithenge_parse_int(state->buffer +
262 state->old_buffer_pos, &state->token_int);
263 error_errno(state, rc);
264 } else if (ch == '<') {
265 state->token = ch;
266 state->buffer_pos++;
267 if (state->buffer[state->buffer_pos] == '-') {
268 state->buffer_pos++;
269 state->token = TOKEN_LEFT_ARROW;
270 }
271 } else if (ch == '=') {
272 state->token = ch;
273 state->buffer_pos++;
274 if (state->buffer[state->buffer_pos] == '=') {
275 state->token = TOKEN_EQUALS;
276 state->buffer_pos++;
277 }
278 } else {
279 state->token = ch;
280 state->buffer_pos++;
281 }
282}
283
284/** Allocate memory and handle failure by setting the error in the state. The
285 * caller must check the state for errors before using the return value of this
286 * function. */
287static void *state_malloc(state_t *state, size_t size)
288{
289 if (state->error != EOK)
290 return NULL;
291 void *result = malloc(size);
292 if (result == NULL)
293 error_errno(state, ENOMEM);
294 return result;
295}
296
297/** Reallocate memory and handle failure by setting the error in the state. If
298 * an error occurs, the existing pointer will be returned. */
299static void *state_realloc(state_t *state, void *ptr, size_t size)
300{
301 if (state->error != EOK)
302 return ptr;
303 void *result = realloc(ptr, size);
304 if (result == NULL) {
305 error_errno(state, ENOMEM);
306 return ptr;
307 }
308 return result;
309}
310
311/** Expect and consume a certain token. If the next token is of the wrong type,
312 * an error is caused. */
313static void expect(state_t *state, token_type_t type)
314{
315 if (state->token != type) {
316 syntax_error(state, "unexpected");
317 return;
318 }
319 next_token(state);
320}
321
322/** Expect and consume an identifier token. If the next token is not an
323 * identifier, an error is caused and this function returns null. */
324static char *expect_identifier(state_t *state)
325{
326 if (state->token != TOKEN_IDENTIFIER) {
327 syntax_error(state, "unexpected (identifier expected)");
328 return NULL;
329 }
330 char *val = state->token_string;
331 state->token_string = NULL;
332 next_token(state);
333 return val;
334}
335
336/** Find a transform by name. A reference will be added to the transform.
337 * @return The found transform, or NULL if none was found. */
338static bithenge_transform_t *get_named_transform(state_t *state,
339 const char *name)
340{
341 for (transform_list_t *e = state->transform_list; e; e = e->next) {
342 if (!str_cmp(e->name, name)) {
343 bithenge_transform_inc_ref(e->transform);
344 return e->transform;
345 }
346 }
347 for (int i = 0; bithenge_primitive_transforms[i].name; i++) {
348 if (!str_cmp(bithenge_primitive_transforms[i].name, name)) {
349 bithenge_transform_t *xform =
350 bithenge_primitive_transforms[i].transform;
351 bithenge_transform_inc_ref(xform);
352 return xform;
353 }
354 }
355 return NULL;
356}
357
358/** Add a named transform. This function takes ownership of the name and a
359 * reference to the transform. If an error has occurred, either may be null. */
360static void add_named_transform(state_t *state, bithenge_transform_t *xform, char *name)
361{
362 transform_list_t *entry = state_malloc(state, sizeof(*entry));
363 if (state->error != EOK) {
364 free(name);
365 bithenge_transform_dec_ref(xform);
366 free(entry);
367 return;
368 }
369 entry->name = name;
370 entry->transform = xform;
371 entry->next = state->transform_list;
372 state->transform_list = entry;
373}
374
375static bithenge_transform_t *parse_transform(state_t *state);
376static bithenge_transform_t *parse_struct(state_t *state);
377static bithenge_expression_t *parse_expression(state_t *state);
378
379
380
381/***************** Expressions *****************/
382
383typedef enum {
384 PRECEDENCE_NONE,
385 PRECEDENCE_EQUALS,
386 PRECEDENCE_ADD,
387 PRECEDENCE_MULTIPLY,
388} precedence_t;
389
390static bithenge_binary_op_t token_as_binary_operator(token_type_t token)
391{
392 switch ((int)token) {
393 case '+':
394 return BITHENGE_EXPRESSION_ADD;
395 case '-':
396 return BITHENGE_EXPRESSION_SUBTRACT;
397 case '*':
398 return BITHENGE_EXPRESSION_MULTIPLY;
399 case TOKEN_EQUALS:
400 return BITHENGE_EXPRESSION_EQUALS;
401 default:
402 return BITHENGE_EXPRESSION_INVALID_BINARY_OP;
403 }
404}
405
406static precedence_t binary_operator_precedence(bithenge_binary_op_t op)
407{
408 switch (op) {
409 case BITHENGE_EXPRESSION_ADD: /* fallthrough */
410 case BITHENGE_EXPRESSION_SUBTRACT:
411 return PRECEDENCE_ADD;
412 case BITHENGE_EXPRESSION_MULTIPLY:
413 return PRECEDENCE_MULTIPLY;
414 case BITHENGE_EXPRESSION_EQUALS:
415 return PRECEDENCE_EQUALS;
416 default:
417 assert(false);
418 return PRECEDENCE_NONE;
419 }
420}
421
422static bithenge_expression_t *parse_term(state_t *state)
423{
424 int rc;
425 if (state->token == TOKEN_TRUE || state->token == TOKEN_FALSE) {
426 bool val = state->token == TOKEN_TRUE;
427 next_token(state);
428 bithenge_node_t *node;
429 rc = bithenge_new_boolean_node(&node, val);
430 if (rc != EOK) {
431 error_errno(state, rc);
432 return NULL;
433 }
434
435 bithenge_expression_t *expr;
436 rc = bithenge_const_expression(&expr, node);
437 if (rc != EOK) {
438 error_errno(state, rc);
439 return NULL;
440 }
441
442 return expr;
443 } else if (state->token == TOKEN_IN) {
444 next_token(state);
445 state->in_node_used = true;
446 bithenge_expression_t *expr;
447 rc = bithenge_in_node_expression(&expr);
448 if (rc != EOK) {
449 error_errno(state, rc);
450 return NULL;
451 }
452 return expr;
453 } else if (state->token == TOKEN_INTEGER) {
454 bithenge_int_t val = state->token_int;
455 next_token(state);
456 bithenge_node_t *node;
457 rc = bithenge_new_integer_node(&node, val);
458 if (rc != EOK) {
459 error_errno(state, rc);
460 return NULL;
461 }
462
463 bithenge_expression_t *expr;
464 rc = bithenge_const_expression(&expr, node);
465 if (rc != EOK) {
466 error_errno(state, rc);
467 return NULL;
468 }
469
470 return expr;
471 } else if (state->token == TOKEN_IDENTIFIER) {
472 int i;
473 for (i = 0; i < state->num_params; i++)
474 if (!str_cmp(state->parameter_names[i],
475 state->token_string))
476 break;
477
478 if (i == state->num_params) {
479 syntax_error(state, "unknown identifier");
480 return NULL;
481 }
482
483 bithenge_expression_t *expr;
484 rc = bithenge_param_expression(&expr, i);
485 if (rc != EOK) {
486 error_errno(state, rc);
487 return NULL;
488 }
489
490 next_token(state);
491
492 return expr;
493 } else if (state->token == '.') {
494 next_token(state);
495
496 const char *id = expect_identifier(state);
497 bithenge_node_t *key = NULL;
498 bithenge_expression_t *expr = NULL;
499
500 if (state->error == EOK) {
501 rc = bithenge_new_string_node(&key, id, true);
502 id = NULL;
503 error_errno(state, rc);
504 }
505
506 if (state->error == EOK) {
507 rc = bithenge_scope_member_expression(&expr, key);
508 key = NULL;
509 if (rc != EOK)
510 expr = NULL;
511 error_errno(state, rc);
512 }
513
514 if (state->error != EOK) {
515 free((char *)id);
516 bithenge_node_dec_ref(key);
517 bithenge_expression_dec_ref(expr);
518 return NULL;
519 }
520
521 return expr;
522 } else if (state->token == '(') {
523 next_token(state);
524 bithenge_expression_t *expr = parse_expression(state);
525 expect(state, ')');
526 return expr;
527 } else {
528 syntax_error(state, "expression expected");
529 return NULL;
530 }
531}
532
533static bithenge_expression_t *parse_postfix_expression(state_t *state)
534{
535 bithenge_expression_t *expr = parse_term(state);
536 while (state->error == EOK) {
537 if (state->token == '[') {
538 next_token(state);
539 bithenge_expression_t *start = parse_expression(state);
540 bool absolute_limit = false;
541 if (state->token == ',') {
542 absolute_limit = false;
543 next_token(state);
544 } else if (state->token == ':') {
545 absolute_limit = true;
546 next_token(state);
547 } else {
548 syntax_error(state, "expected ',' or ':'");
549 }
550 bithenge_expression_t *limit = NULL;
551 if (!(state->token == ']' && absolute_limit))
552 limit = parse_expression(state);
553 expect(state, ']');
554
555 if (state->error != EOK) {
556 bithenge_expression_dec_ref(expr);
557 bithenge_expression_dec_ref(start);
558 bithenge_expression_dec_ref(limit);
559 return NULL;
560 }
561 int rc = bithenge_subblob_expression(&expr, expr,
562 start, limit, absolute_limit);
563 if (rc != EOK) {
564 error_errno(state, rc);
565 return NULL;
566 }
567 } else {
568 break;
569 }
570 }
571 return expr;
572}
573
574static bithenge_expression_t *parse_expression_precedence(state_t *state,
575 precedence_t prev_precedence)
576{
577 bithenge_expression_t *expr = parse_postfix_expression(state);
578 while (state->error == EOK) {
579 bithenge_binary_op_t op =
580 token_as_binary_operator(state->token);
581 if (op == BITHENGE_EXPRESSION_INVALID_BINARY_OP)
582 break;
583 precedence_t precedence = binary_operator_precedence(op);
584 if (precedence <= prev_precedence)
585 break;
586 next_token(state);
587
588 bithenge_expression_t *expr2 = parse_postfix_expression(state);
589 if (state->error != EOK) {
590 bithenge_expression_dec_ref(expr2);
591 break;
592 }
593 int rc = bithenge_binary_expression(&expr, op, expr, expr2);
594 if (rc != EOK)
595 error_errno(state, rc);
596 }
597 if (state->error != EOK) {
598 bithenge_expression_dec_ref(expr);
599 expr = NULL;
600 }
601 return expr;
602}
603
604static bithenge_expression_t *parse_expression(state_t *state)
605{
606 return parse_expression_precedence(state, PRECEDENCE_NONE);
607}
608
609
610
611/* state->token must be TOKEN_IDENTIFIER when this is called. */
612static bithenge_transform_t *parse_invocation(state_t *state)
613{
614 bithenge_transform_t *result = get_named_transform(state,
615 state->token_string);
616 if (!result)
617 syntax_error(state, "transform not found");
618 next_token(state);
619
620 bithenge_expression_t **params = NULL;
621 int num_params = 0;
622 if (state->token == '(') {
623 next_token(state);
624 while (state->error == EOK && state->token != ')') {
625 if (num_params)
626 expect(state, ',');
627 params = state_realloc(state, params,
628 (num_params + 1)*sizeof(*params));
629 if (state->error != EOK)
630 break;
631 params[num_params] = parse_expression(state);
632 num_params++;
633 }
634 expect(state, ')');
635 }
636
637 /* TODO: show correct error position */
638 if (state->error == EOK
639 && bithenge_transform_num_params(result) != num_params)
640 syntax_error(state, "incorrect number of parameters before");
641
642 if (state->error != EOK) {
643 while (num_params--)
644 bithenge_expression_dec_ref(params[num_params]);
645 free(params);
646 bithenge_transform_dec_ref(result);
647 return NULL;
648 }
649
650 if (num_params) {
651 int rc = bithenge_param_wrapper(&result, result, params);
652 if (rc != EOK) {
653 error_errno(state, rc);
654 result = NULL;
655 }
656 }
657
658 return result;
659}
660
661/** Create a transform that just produces an empty node.
662 * @param state The parser state.
663 * @return The new transform, or NULL on error. */
664static bithenge_transform_t *make_empty_transform(state_t *state)
665{
666 bithenge_node_t *node;
667 int rc = bithenge_new_empty_internal_node(&node);
668 if (rc != EOK) {
669 error_errno(state, rc);
670 return NULL;
671 }
672
673 bithenge_expression_t *expr;
674 rc = bithenge_const_expression(&expr, node);
675 if (rc != EOK) {
676 error_errno(state, rc);
677 return NULL;
678 }
679
680 bithenge_transform_t *xform;
681 rc = bithenge_inputless_transform(&xform, expr);
682 if (rc != EOK) {
683 error_errno(state, rc);
684 return NULL;
685 }
686
687 return xform;
688}
689
690static bithenge_transform_t *parse_if(state_t *state, bool in_struct)
691{
692 expect(state, TOKEN_IF);
693 expect(state, '(');
694 bithenge_expression_t *expr = parse_expression(state);
695 expect(state, ')');
696 expect(state, '{');
697 bithenge_transform_t *true_xform =
698 in_struct ? parse_struct(state) : parse_transform(state);
699 expect(state, '}');
700
701 bithenge_transform_t *false_xform = NULL;
702 if (state->token == TOKEN_ELSE) {
703 next_token(state);
704 expect(state, '{');
705 false_xform =
706 in_struct ? parse_struct(state) : parse_transform(state);
707 expect(state, '}');
708 } else {
709 if (in_struct)
710 false_xform = make_empty_transform(state);
711 else
712 syntax_error(state, "else expected");
713 }
714
715 if (state->error != EOK) {
716 bithenge_expression_dec_ref(expr);
717 bithenge_transform_dec_ref(true_xform);
718 bithenge_transform_dec_ref(false_xform);
719 return NULL;
720 }
721
722 bithenge_transform_t *if_xform;
723 int rc = bithenge_if_transform(&if_xform, expr, true_xform,
724 false_xform);
725 if (rc != EOK) {
726 error_errno(state, rc);
727 return NULL;
728 }
729 return if_xform;
730}
731
732static bithenge_transform_t *parse_switch(state_t *state, bool in_struct)
733{
734 expect(state, TOKEN_SWITCH);
735 expect(state, '(');
736 bithenge_expression_t *ref_expr = parse_expression(state);
737 expect(state, ')');
738 expect(state, '{');
739 int num = 0;
740 bithenge_expression_t **exprs = NULL;
741 bithenge_transform_t **xforms = NULL;
742 while (state->error == EOK && state->token != '}') {
743 bithenge_expression_t *expr;
744 if (state->token == TOKEN_ELSE) {
745 next_token(state);
746 bithenge_node_t *node;
747 int rc = bithenge_new_boolean_node(&node, true);
748 if (rc != EOK) {
749 error_errno(state, rc);
750 break;
751 }
752 rc = bithenge_const_expression(&expr, node);
753 if (rc != EOK) {
754 error_errno(state, rc);
755 break;
756 }
757 } else {
758 expr = parse_expression(state);
759 if (state->error == EOK) {
760 bithenge_expression_inc_ref(ref_expr);
761 int rc = bithenge_binary_expression(&expr,
762 BITHENGE_EXPRESSION_EQUALS, ref_expr,
763 expr);
764 if (rc != EOK) {
765 error_errno(state, rc);
766 break;
767 }
768 }
769 }
770
771 expect(state, ':');
772 bithenge_transform_t *xform;
773 if (in_struct) {
774 expect(state, '{');
775 xform = parse_struct(state);
776 expect(state, '}');
777 } else
778 xform = parse_transform(state);
779 expect(state, ';');
780
781 exprs = state_realloc(state, exprs,
782 sizeof(*exprs) * (num + 1));
783 xforms = state_realloc(state, xforms,
784 sizeof(*xforms) * (num + 1));
785 if (state->error != EOK) {
786 bithenge_expression_dec_ref(expr);
787 bithenge_transform_dec_ref(xform);
788 break;
789 }
790
791 exprs[num] = expr;
792 xforms[num] = xform;
793 num++;
794 }
795 bithenge_expression_dec_ref(ref_expr);
796
797 bithenge_transform_t *switch_xform = &bithenge_invalid_transform;
798 bithenge_transform_inc_ref(switch_xform);
799 while (state->error == EOK && num >= 1) {
800 num--;
801 int rc = bithenge_if_transform(&switch_xform, exprs[num],
802 xforms[num], switch_xform);
803 if (rc != EOK)
804 error_errno(state, rc);
805 }
806
807 while (num >= 1) {
808 num--;
809 bithenge_expression_dec_ref(exprs[num]);
810 bithenge_transform_dec_ref(xforms[num]);
811 }
812 free(exprs);
813 free(xforms);
814
815 expect(state, '}');
816 return switch_xform;
817}
818
819static bithenge_transform_t *parse_repeat(state_t *state)
820{
821 expect(state, TOKEN_REPEAT);
822 bithenge_expression_t *expr = NULL;
823 if (state->token == '(') {
824 next_token(state);
825 expr = parse_expression(state);
826 expect(state, ')');
827 }
828 expect(state, '{');
829 bithenge_transform_t *xform = parse_transform(state);
830 expect(state, '}');
831
832 if (state->error != EOK) {
833 bithenge_expression_dec_ref(expr);
834 bithenge_transform_dec_ref(xform);
835 return NULL;
836 }
837
838 bithenge_transform_t *repeat_xform;
839 int rc = bithenge_repeat_transform(&repeat_xform, xform, expr);
840 if (rc != EOK) {
841 error_errno(state, rc);
842 return NULL;
843 }
844 return repeat_xform;
845}
846
847static bithenge_transform_t *parse_do_while(state_t *state)
848{
849 expect(state, TOKEN_DO);
850 expect(state, '{');
851 bithenge_transform_t *xform = parse_transform(state);
852 expect(state, '}');
853 expect(state, TOKEN_WHILE);
854 expect(state, '(');
855 bithenge_expression_t *expr = parse_expression(state);
856 expect(state, ')');
857
858 if (state->error != EOK) {
859 bithenge_expression_dec_ref(expr);
860 bithenge_transform_dec_ref(xform);
861 return NULL;
862 }
863
864 bithenge_transform_t *do_while_xform;
865 int rc = bithenge_do_while_transform(&do_while_xform, xform, expr);
866 if (rc != EOK) {
867 error_errno(state, rc);
868 return NULL;
869 }
870 return do_while_xform;
871}
872
873/* The TOKEN_STRUCT and '{' must already have been skipped. */
874static bithenge_transform_t *parse_struct(state_t *state)
875{
876 size_t num = 0;
877 bithenge_named_transform_t *subxforms;
878 /* We keep an extra space for the {NULL, NULL} terminator. */
879 subxforms = state_malloc(state, sizeof(*subxforms));
880 while (state->error == EOK && state->token != '}') {
881 if (state->token == TOKEN_IF) {
882 subxforms[num].transform = parse_if(state, true);
883 subxforms[num].name = NULL;
884 } else if (state->token == TOKEN_SWITCH) {
885 subxforms[num].transform = parse_switch(state, true);
886 subxforms[num].name = NULL;
887 } else {
888 if (state->token == '.') {
889 next_token(state);
890 subxforms[num].name = expect_identifier(state);
891 } else {
892 subxforms[num].name = NULL;
893 }
894 expect(state, TOKEN_LEFT_ARROW);
895 subxforms[num].transform = parse_transform(state);
896 expect(state, ';');
897 }
898 num++;
899 subxforms = state_realloc(state, subxforms,
900 (num + 1)*sizeof(*subxforms));
901 }
902
903 if (state->error != EOK) {
904 while (num--) {
905 free((void *)subxforms[num].name);
906 bithenge_transform_dec_ref(subxforms[num].transform);
907 }
908 free(subxforms);
909 return NULL;
910 }
911
912 subxforms[num].name = NULL;
913 subxforms[num].transform = NULL;
914 bithenge_transform_t *result;
915 int rc = bithenge_new_struct(&result, subxforms);
916 if (rc != EOK) {
917 error_errno(state, rc);
918 return NULL;
919 }
920 return result;
921}
922
923/** Parse a transform without composition.
924 * @return The parsed transform, or NULL if an error occurred. */
925static bithenge_transform_t *parse_transform_no_compose(state_t *state)
926{
927 if (state->token == '(') {
928 next_token(state);
929 state->in_node_used = false;
930 bithenge_expression_t *expr = parse_expression(state);
931 expect(state, ')');
932 if (state->error != EOK) {
933 bithenge_expression_dec_ref(expr);
934 return NULL;
935 }
936
937 bithenge_transform_t *xform;
938 int rc;
939 if (state->in_node_used)
940 rc = bithenge_expression_transform(&xform, expr);
941 else
942 rc = bithenge_inputless_transform(&xform, expr);
943 if (rc != EOK) {
944 error_errno(state, rc);
945 return NULL;
946 }
947 return xform;
948 } else if (state->token == TOKEN_DO) {
949 return parse_do_while(state);
950 } else if (state->token == TOKEN_IDENTIFIER) {
951 return parse_invocation(state);
952 } else if (state->token == TOKEN_IF) {
953 return parse_if(state, false);
954 } else if (state->token == TOKEN_REPEAT) {
955 return parse_repeat(state);
956 } else if (state->token == TOKEN_STRUCT) {
957 next_token(state);
958 expect(state, '{');
959 bithenge_transform_t *xform = parse_struct(state);
960 expect(state, '}');
961 return xform;
962 } else if (state->token == TOKEN_SWITCH) {
963 return parse_switch(state, false);
964 } else {
965 syntax_error(state, "unexpected (transform expected)");
966 return NULL;
967 }
968}
969
970/** Parse a transform.
971 * @return The parsed transform, or NULL if an error occurred. */
972static bithenge_transform_t *parse_transform(state_t *state)
973{
974 bithenge_transform_t *result = parse_transform_no_compose(state);
975 bithenge_transform_t **xforms = NULL;
976 size_t num = 1;
977 while (state->token == TOKEN_LEFT_ARROW) {
978 expect(state, TOKEN_LEFT_ARROW);
979 xforms = state_realloc(state, xforms,
980 (num + 1) * sizeof(*xforms));
981 if (state->error != EOK)
982 break;
983 xforms[num] = parse_transform_no_compose(state);
984 num++;
985 }
986 if (state->error != EOK) {
987 while (xforms && num--)
988 bithenge_transform_dec_ref(xforms[num]);
989 free(xforms);
990 bithenge_transform_dec_ref(result);
991 return NULL;
992 }
993 if (xforms) {
994 xforms[0] = result;
995 int rc = bithenge_new_composed_transform(&result, xforms, num);
996 if (rc != EOK) {
997 error_errno(state, rc);
998 return NULL;
999 }
1000 }
1001 return result;
1002}
1003
1004/** Parse a definition. */
1005static void parse_definition(state_t *state)
1006{
1007 expect(state, TOKEN_TRANSFORM);
1008 char *name = expect_identifier(state);
1009
1010 if (state->token == '(') {
1011 next_token(state);
1012 while (state->error == EOK && state->token != ')') {
1013 if (state->num_params)
1014 expect(state, ',');
1015 state->parameter_names = state_realloc(state,
1016 state->parameter_names,
1017 (state->num_params + 1)*sizeof(*state->parameter_names));
1018 if (state->error != EOK)
1019 break;
1020 state->parameter_names[state->num_params++] =
1021 expect_identifier(state);
1022 }
1023 expect(state, ')');
1024 }
1025
1026 expect(state, '=');
1027 bithenge_transform_t *xform = parse_transform(state);
1028 expect(state, ';');
1029
1030 if (state->error == EOK) {
1031 int rc = bithenge_new_barrier_transform(&xform, xform,
1032 state->num_params);
1033 if (rc != EOK) {
1034 xform = NULL;
1035 error_errno(state, rc);
1036 }
1037 }
1038
1039 add_named_transform(state, xform, name);
1040
1041 for (int i = 0; i < state->num_params; i++)
1042 free(state->parameter_names[i]);
1043 free(state->parameter_names);
1044 state->parameter_names = NULL;
1045 state->num_params = 0;
1046}
1047
1048/** Initialize the state. */
1049static void state_init(state_t *state, const char *filename)
1050{
1051 state->error = EOK;
1052 state->transform_list = NULL;
1053 state->parameter_names = NULL;
1054 state->num_params = 0;
1055 state->token = TOKEN_ERROR;
1056 state->old_buffer_pos = state->buffer_pos = BUFFER_SIZE - 1;
1057 state->lineno = 1;
1058 state->line_offset = (int)-state->buffer_pos + 1;
1059 state->filename = filename;
1060 state->file = fopen(filename, "r");
1061 if (!state->file) {
1062 error_errno(state, errno);
1063 } else {
1064 next_token(state);
1065 }
1066}
1067
1068/** Destroy the state. */
1069static void state_destroy(state_t *state)
1070{
1071 done_with_token(state);
1072 state->token = TOKEN_ERROR;
1073 if (state->file)
1074 fclose(state->file);
1075 transform_list_t *entry = state->transform_list;
1076 while (entry) {
1077 transform_list_t *next = entry->next;
1078 free(entry->name);
1079 bithenge_transform_dec_ref(entry->transform);
1080 free(entry);
1081 entry = next;
1082 }
1083 for (int i = 0; i < state->num_params; i++)
1084 free(state->parameter_names[i]);
1085 free(state->parameter_names);
1086}
1087
1088/** Parse a script file.
1089 * @param filename The name of the script file.
1090 * @param[out] out Stores the "main" transform.
1091 * @return EOK on success, EINVAL on syntax error, or an error code from
1092 * errno.h. */
1093int bithenge_parse_script(const char *filename, bithenge_transform_t **out)
1094{
1095 state_t state;
1096 state_init(&state, filename);
1097 while (state.error == EOK && state.token != TOKEN_EOF)
1098 parse_definition(&state);
1099 *out = get_named_transform(&state, "main");
1100 int rc = state.error;
1101 state_destroy(&state);
1102 if (rc == EOK && !*out) {
1103 fprintf(stderr, "no \"main\" transform\n");
1104 rc = EINVAL;
1105 }
1106 return rc;
1107}
1108
1109/** @}
1110 */
Note: See TracBrowser for help on using the repository browser.