source: mainline/uspace/app/bithenge/script.c@ 6be4142

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

Bithenge: more FAT, operators, and fixes

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