2 * Copyright © 2016 Keith Packard <keithp@keithp.com>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
16 #include "ao_lisp_read.h"
18 static const uint16_t lex_classes[128] = {
51 PRINTABLE|WHITE, /* */
53 PRINTABLE|STRINGC, /* " */
54 PRINTABLE|POUND, /* # */
58 PRINTABLE|SPECIAL, /* ' */
59 PRINTABLE|SPECIAL, /* ( */
60 PRINTABLE|SPECIAL, /* ) */
62 PRINTABLE|SIGN, /* + */
64 PRINTABLE|SIGN, /* - */
65 PRINTABLE|SPECIAL, /* . */
67 PRINTABLE|DIGIT, /* 0 */
68 PRINTABLE|DIGIT, /* 1 */
69 PRINTABLE|DIGIT, /* 2 */
70 PRINTABLE|DIGIT, /* 3 */
71 PRINTABLE|DIGIT, /* 4 */
72 PRINTABLE|DIGIT, /* 5 */
73 PRINTABLE|DIGIT, /* 6 */
74 PRINTABLE|DIGIT, /* 7 */
75 PRINTABLE|DIGIT, /* 8 */
76 PRINTABLE|DIGIT, /* 9 */
78 PRINTABLE|COMMENT, /* ; */
111 PRINTABLE|BACKSLASH, /* \ */
143 PRINTABLE|VBAR, /* | */
149 static int lex_unget_c;
171 static uint16_t lex_class;
181 lex_class = ENDOFFILE;
184 lex_class = lex_classes[c];
186 } while (lex_class & IGNORE);
199 lex_class = ENDOFFILE;
232 if (c < '0' || '7' < c) {
236 v = (v << 3) + c - '0';
245 #define AO_LISP_TOKEN_MAX 32
247 static char token_string[AO_LISP_TOKEN_MAX];
248 static int token_int;
249 static int token_len;
251 static inline void add_token(int c) {
252 if (c && token_len < AO_LISP_TOKEN_MAX - 1)
253 token_string[token_len++] = c;
256 static inline void end_token(void) {
257 token_string[token_len] = '\0';
268 if (lex_class & ENDOFFILE)
271 if (lex_class & WHITE)
274 if (lex_class & COMMENT) {
275 while ((c = lexc()) != '\n') {
276 if (lex_class & ENDOFFILE)
282 if (lex_class & SPECIAL) {
298 if (lex_class & POUND) {
313 alphabetic = (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'));
314 if (token_len == 0) {
329 token_int = token_string[0];
330 else if (!strcmp(token_string, "space"))
332 else if (!strcmp(token_string, "newline"))
334 else if (!strcmp(token_string, "tab"))
336 else if (!strcmp(token_string, "return"))
338 else if (!strcmp(token_string, "formfeed"))
341 ao_lisp_error(AO_LISP_INVALID, "invalid character token #\\%s", token_string);
347 if (lex_class & STRINGC) {
350 if (lex_class & BACKSLASH)
352 if (lex_class & (STRINGC|ENDOFFILE)) {
359 if (lex_class & PRINTABLE) {
369 if (!(lex_class & NUMBER)) {
372 if (token_len != 0 &&
379 if (lex_class & DIGIT) {
382 token_int = token_int * 10 + c - '0';
387 if (lex_class & (NOTNAME)) {
388 // if (lex_class & ENDOFFILE)
392 if (isnum && hasdigit) {
394 token_int = -token_int;
405 static inline int lex(void)
407 int parse_token = _lex();
408 DBGI("token %d (%s)\n", parse_token, token_string);
412 static int parse_token;
414 struct ao_lisp_cons *ao_lisp_read_cons;
415 struct ao_lisp_cons *ao_lisp_read_cons_tail;
416 struct ao_lisp_cons *ao_lisp_read_stack;
418 #define READ_IN_QUOTE 0x01
419 #define READ_SAW_DOT 0x02
420 #define READ_DONE_DOT 0x04
423 push_read_stack(int cons, int read_state)
425 DBGI("push read stack %p 0x%x\n", ao_lisp_read_cons, read_state);
428 ao_lisp_read_stack = ao_lisp_cons_cons(ao_lisp_cons_poly(ao_lisp_read_cons),
429 ao_lisp__cons(ao_lisp_int_poly(read_state),
430 ao_lisp_cons_poly(ao_lisp_read_stack)));
431 if (!ao_lisp_read_stack)
434 ao_lisp_read_cons = NULL;
435 ao_lisp_read_cons_tail = NULL;
440 pop_read_stack(int cons)
444 ao_lisp_read_cons = ao_lisp_poly_cons(ao_lisp_read_stack->car);
445 ao_lisp_read_stack = ao_lisp_poly_cons(ao_lisp_read_stack->cdr);
446 read_state = ao_lisp_poly_int(ao_lisp_read_stack->car);
447 ao_lisp_read_stack = ao_lisp_poly_cons(ao_lisp_read_stack->cdr);
448 for (ao_lisp_read_cons_tail = ao_lisp_read_cons;
449 ao_lisp_read_cons_tail && ao_lisp_read_cons_tail->cdr;
450 ao_lisp_read_cons_tail = ao_lisp_poly_cons(ao_lisp_read_cons_tail->cdr))
453 ao_lisp_read_cons = 0;
454 ao_lisp_read_cons_tail = 0;
455 ao_lisp_read_stack = 0;
458 DBGI("pop read stack %p %d\n", ao_lisp_read_cons, read_state);
465 struct ao_lisp_atom *atom;
474 ao_lisp_read_cons = ao_lisp_read_cons_tail = ao_lisp_read_stack = 0;
477 while (parse_token == OPEN) {
478 if (!push_read_stack(cons, read_state))
485 switch (parse_token) {
489 ao_lisp_error(AO_LISP_EOF, "unexpected end of file");
490 return _ao_lisp_atom_eof;
493 atom = ao_lisp_atom_intern(token_string);
495 v = ao_lisp_atom_poly(atom);
500 v = ao_lisp_int_poly(token_int);
503 if (token_string[0] == 't')
504 v = _ao_lisp_bool_true;
506 v = _ao_lisp_bool_false;
509 string = ao_lisp_string_copy(token_string);
511 v = ao_lisp_string_poly(string);
516 if (!push_read_stack(cons, read_state))
519 read_state |= READ_IN_QUOTE;
520 v = _ao_lisp_atom_quote;
527 v = ao_lisp_cons_poly(ao_lisp_read_cons);
529 read_state = pop_read_stack(cons);
533 ao_lisp_error(AO_LISP_INVALID, ". outside of cons");
536 if (!ao_lisp_read_cons) {
537 ao_lisp_error(AO_LISP_INVALID, ". first in cons");
540 read_state |= READ_SAW_DOT;
544 /* loop over QUOTE ends */
549 if (read_state & READ_DONE_DOT) {
550 ao_lisp_error(AO_LISP_INVALID, ". not last in cons");
554 if (read_state & READ_SAW_DOT) {
555 read_state |= READ_DONE_DOT;
556 ao_lisp_read_cons_tail->cdr = v;
558 struct ao_lisp_cons *read = ao_lisp_cons_cons(v, AO_LISP_NIL);
562 if (ao_lisp_read_cons_tail)
563 ao_lisp_read_cons_tail->cdr = ao_lisp_cons_poly(read);
565 ao_lisp_read_cons = read;
566 ao_lisp_read_cons_tail = read;
569 if (!(read_state & READ_IN_QUOTE) || !ao_lisp_read_cons->cdr)
572 v = ao_lisp_cons_poly(ao_lisp_read_cons);
574 read_state = pop_read_stack(cons);