source: mainline/uspace/app/bithenge/script.c@ c54f5d0

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

Bithenge: partial transforms

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