source: mainline/uspace/lib/bithenge/src/script.c@ d1582b50

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since d1582b50 was d1582b50, checked in by Jiri Svoboda <jiri@…>, 5 years ago

Fix spacing in single-line comments using latest ccheck

This found incorrectly formatted section comments (with blocks of
asterisks or dashes). I strongly believe against using section comments
but I am not simply removing them since that would probably be
controversial.

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