read.c 16.4 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/*
 * Cherry programming language
 * Copyright (C) 2013 Christoph Mueller
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
18
#include "cherry.h"
19

20
#include "cherry/unicode.h"
21
#include "cherry/array.h"
22
23
24
25
26
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
27
#include <gc.h>
28

29
struct org_cherry_context*   
30
org_cherry_context(const cy_byte_t* source, const char* filename, cy_flags_t flags)
31
{
32
	struct org_cherry_context* context = GC_MALLOC(sizeof(struct org_cherry_context));
33
34
	context->filename = filename;
	context->begin = source;
35
36
	context->src = (cy_byte_t*) source;
	context->buffer = org_cherry_array_new(sizeof(cy_byte_t));
37
	context->flags = flags;
38
39
40
41
42

	return context;
}


43
struct org_cherry_context*   
44
org_cherry_context_repl(const cy_byte_t* source)
45
{
46
	return org_cherry_context(source, 0, CY_SUPRESS_COMMENTS);
47
48
49
50
}


void                
51
org_cherry_error(struct org_cherry_context* context, const char* format, ...)
52
53
54
55
{
	va_list args;
	va_start(args, format);

56
57
	if(context->filename != 0)
		fprintf(stderr, "ERROR %s", context->filename); 
58
	else
59
		fprintf(stderr, "ERROR (console)");
60
61
62

	fprintf(stderr, ": ");
	vfprintf(stderr, format, args);
63
	fprintf(stderr, "\n");
64
65
66
67

	va_end(args);
}

Chris Müller's avatar
Chris Müller committed
68
69

struct Mapping {
70
	cy_byte_t* string;
71
	enum org_cherry_tok value;
Chris Müller's avatar
Chris Müller committed
72
73
74
75
};



76
const cy_byte_t*      
77
org_cherry_tok_to_string(enum org_cherry_tok token)
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
{
	switch(token) {
		case TOK_EOF:
			return "EOF";
		case TOK_COMMENT:
			return "COMMENT";
		case TOK_ROUNDLEFTBRACE:
			return "(";
		case TOK_ROUNDRIGHTBRACE:
			return ")";
		case TOK_SQUARELEFTBRACE:
			return "[";
		case TOK_SQUARERIGHTBRACE:
			return "]";
		case TOK_STRING:
			return "STRING";
		case TOK_DOT:
			return ".";
		case TOK_CHAR:
			return "CHAR";
		case TOK_HEX:
			return "HEX";
		case TOK_DEC:
			return "DEC";
		case TOK_OCT:
			return "OCT";
		case TOK_BIN:
			return "BIN";
		case TOK_FLOAT:
			return "FLOAT";
Chris Müller's avatar
Chris Müller committed
108
109
		case TOK_SYMBOL:
			return "SYMBOL";
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
	}

	return "UNKNOWN";
}


enum FloatState {
	FP_START, 
	FP_EXPONENT, 
	FP_DOT, 
	FP_DECIMAL, 
	FP_MINUSPLUS, 
	FP_FINAL
};


126
127
static enum org_cherry_tok
lex_float(struct org_cherry_context* context)
128
{
129
	struct org_cherry_array* buffer = context->buffer;
130
131
	const cy_byte_t* p = context->src;
	cy_unicode_t ch = org_cherry_utf8_get(p);
132
133
134
135
136
137
138
139
140
141

	enum FloatState state = FP_START;

	do {
		switch(state) {
			case FP_START:
				if(ch == 'e' || ch == 'E')
					state = FP_EXPONENT;
				else if(ch == '.')
					state = FP_DOT;
142
143
                else
                    assert(0);
144
145
146
147
148
149
				break;

			case FP_EXPONENT:
				if(ch == '+' || ch == '-')
					state = FP_MINUSPLUS;
				else if('0' > ch || ch > '9') {
150
					org_cherry_error(context, "Unexpected character found in float literal after +/-");
151
					org_cherry_array_append(buffer, "0", 1);
152
153
154
155
156
157
158
159
					goto RETURN_TOKEN;
				} else
					state = FP_FINAL;
				break;

			case FP_DOT:
				state = FP_DECIMAL;
				if('0' > ch || ch > '9') {
160
					org_cherry_error(context, "Unexpected character found in float literal after dot");
161
					org_cherry_array_append(buffer, "0", 1);
162
163
164
165
166
167
168
169
170
171
172
173
174
175
					goto RETURN_TOKEN;
				}
				break;

			case FP_DECIMAL:
				if(ch == 'e' || ch == 'E') 
					state = FP_EXPONENT;
				else if('0' > ch || ch > '9')
					goto RETURN_TOKEN;
				break;

			case FP_MINUSPLUS:
				state = FP_FINAL;
				if('0' > ch || ch > '9') {
176
					org_cherry_error(context, "Unexpected character found in float literal");
177
					org_cherry_array_append(buffer, "0", 1);
178
179
180
181
182
183
184
185
186
187
					goto RETURN_TOKEN;
				}
				break;

			case FP_FINAL:
				if('0' > ch || ch > '9')
					goto RETURN_TOKEN;
				break;
		}

188
		org_cherry_array_append(buffer, p, 1);
189
190

NO_APPEND_BUFFER:
191
192
		p = org_cherry_utf8_next(p);
		ch = org_cherry_utf8_get(p);
193
194
195
196
197
198

	} while (ch != '\0');

RETURN_TOKEN:
	context->src = p;

199
	org_cherry_array_append(buffer, "\0", 1);
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217

	return TOK_FLOAT;
}


enum NumberState {
	INT_START, 
	INT_BASE, 
	INT_BIN_WAIT, 
	INT_HEX_WAIT, 
	INT_OCT_WAIT, 
	INT_BIN_READ, 
	INT_HEX_READ, 
	INT_OCT_READ, 
	INT_DEC_READ
};


218
219
static enum org_cherry_tok
lex_number(struct org_cherry_context* context)
220
{
221
	struct org_cherry_array* buffer = context->buffer;
222
223
	const cy_byte_t* p = context->src;
	cy_unicode_t ch = org_cherry_utf8_get(p);
224

225
	enum org_cherry_tok token = TOK_DEC;
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
	enum NumberState state = INT_START;

	do {
		switch(state) {
			case INT_START:
				if(ch == '0') 
					state = INT_BASE;
				else
					state = INT_DEC_READ;
				break;

			case INT_BASE:
				if(ch == 'x') {
					state = INT_HEX_WAIT;
				} else if(ch == 'b') {
					state = INT_BIN_WAIT;
				} else if('0' <= ch && ch <= '7') {
					state = INT_OCT_READ;
					break;
				} else if(ch == '.' || ch == 'e' || ch == 'E') {
					context->src = p;
					return lex_float(context);
				} else {
					token = TOK_DEC;
					goto RETURN_TOKEN;
				}
				break;

			case INT_HEX_WAIT:
				if(('0' > ch || ch > '9') && ('A' > ch || ch > 'F')) {
256
					org_cherry_error(context, "Unexpected character found in hex literal");
257
					org_cherry_array_append(buffer, "0", 1);
258
259
260
261
262
263
264
265
					token = TOK_HEX;
					goto RETURN_TOKEN;
				}
				state = INT_HEX_READ;
				break;

			case INT_BIN_WAIT:
				if(ch != '0' && ch != '1') {
266
					org_cherry_error(context, "Unexpected character found in binary literal");
267
					org_cherry_array_append(buffer, "0", 1);
268
269
270
271
272
273
274
275
					token = TOK_BIN;
					goto RETURN_TOKEN;
				}
				state = INT_BIN_READ;
				break;

			case INT_BIN_READ:
				token = TOK_BIN;
Chris Müller's avatar
Chris Müller committed
276
				if(ch != '0' && ch != '1')
277
278
279
280
281
					goto RETURN_TOKEN;
				break;

			case INT_OCT_READ:
				token = TOK_OCT;
Chris Müller's avatar
Chris Müller committed
282
				if('0' > ch || ch > '7')
283
284
285
286
287
288
289
290
					goto RETURN_TOKEN;
				break;

			case INT_DEC_READ:
				token = TOK_DEC;
				if(ch == '.' || ch == 'e' || ch == 'E') {
					context->src = p;
					return lex_float(context);
Chris Müller's avatar
Chris Müller committed
291
				} else if('0' > ch || ch > '9')
292
293
294
295
296
					goto RETURN_TOKEN;
				break;

			case INT_HEX_READ:
				token = TOK_HEX;
Chris Müller's avatar
Chris Müller committed
297
				if(('0' > ch || ch > '9') && ('A' > ch || ch > 'F'))
298
299
300
301
302
303
304
					goto RETURN_TOKEN;
				break;

			default:
				break;
		}

305
		org_cherry_array_append(buffer, p, 1);
306
307

NO_APPEND_BUFFER:
308
309
		p = org_cherry_utf8_next(p);
		ch = org_cherry_utf8_get(p);
310
311
312
313
	} while(ch != '\0');

RETURN_TOKEN:
	context->src = p;
314
	org_cherry_array_append(buffer, "\0", 1);
315
316
317
318
319

	return token;
}


Chris Müller's avatar
Chris Müller committed
320
321
322
323
324
325
enum CharState {
	CHAR_EAT,
	CHAR_ESCAPE,
	CHAR_UNICODE
};

326
327
static enum org_cherry_tok
lex_character(struct org_cherry_context* context)
Chris Müller's avatar
Chris Müller committed
328
329
330
{
	assert(context != 0);

331
	struct org_cherry_array* buffer = context->buffer;
332
333
	cy_byte_t* p = org_cherry_utf8_next(context->src);
	cy_unicode_t ch = org_cherry_utf8_get(p);
Chris Müller's avatar
Chris Müller committed
334
335
336
	enum CharState state = CHAR_EAT;
	int unicount = 0;

337
    org_cherry_array_append(buffer, "\\", 1);
Chris Müller's avatar
Chris Müller committed
338

339
	while(!org_cherry_unicode_isspace(ch) && ch != '\0') {
Chris Müller's avatar
Chris Müller committed
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
		switch(state) {
			case CHAR_EAT:
				if(ch == 'u') {
					state = CHAR_UNICODE;
					unicount = 4;
				} else if(ch == 'U') {
					state = CHAR_UNICODE;
					unicount = 6;					
				} else {
					state = CHAR_ESCAPE;
				}
				break;
			case CHAR_UNICODE:
				if(unicount-- == 0)
					goto RETURN_TOKEN;

				if(('0' > ch || ch > '9') && ('A' > ch || ch > 'F')) {
357
					org_cherry_error(context, "Unexpected hex sequence in unicode escape sequence");
358
					org_cherry_array_append(buffer, "0", 1);
Chris Müller's avatar
Chris Müller committed
359
360
361
362
363
364
365
366
					goto NO_BUFFER_APPEND;
				}
				break;

			case CHAR_ESCAPE:
				break;
		}

367
		org_cherry_array_append(buffer, p, org_cherry_utf8_codepoints(p));
Chris Müller's avatar
Chris Müller committed
368
369
NO_BUFFER_APPEND:

370
371
		p = org_cherry_utf8_next(p);
		ch = org_cherry_utf8_get(p);
Chris Müller's avatar
Chris Müller committed
372
373
374
375
	}

RETURN_TOKEN:
	if(state == CHAR_UNICODE && unicount > 0) {
376
		org_cherry_error(context, "Improper unicode escape sequence found in character literal");
Chris Müller's avatar
Chris Müller committed
377
378

		while(unicount-- > 0)
379
380
			org_cherry_array_append(buffer, "0", 1);
	} else if(org_cherry_array_size(buffer) == 1) {
381
		org_cherry_error(context, "No character symbol is given in character literal");
382
		org_cherry_array_append(buffer, "0", 1);
Chris Müller's avatar
Chris Müller committed
383
384
	}

385
	org_cherry_array_append(buffer, "\0", 1);
Chris Müller's avatar
Chris Müller committed
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400

	context->src = p;

	return TOK_CHAR;
}


enum StringState {
	STR_EAT, 
	STR_ESCAPE, 
	STR_UNICODE, 
	STR_FINAL
};


401
402
static enum org_cherry_tok
lex_string(struct org_cherry_context* context)
Chris Müller's avatar
Chris Müller committed
403
404
405
{
	assert(context != 0);

406
	struct org_cherry_array* buffer = context->buffer;
Chris Müller's avatar
Chris Müller committed
407
	enum StringState state = STR_EAT;
408
409
	cy_byte_t* p = org_cherry_utf8_next(context->src);
	cy_unicode_t ch = org_cherry_utf8_get(p);
Chris Müller's avatar
Chris Müller committed
410
411
412
413
414
415
416
417
418
419
420
	int unicount = 0;

	while(ch != '\0') {
		switch(state) {
			case STR_EAT:
				if(ch == '\\') 
					state = STR_ESCAPE;
				else if(ch == '\"') {
					state = STR_FINAL;
					goto NO_BUFFER_APPEND;
				} else if(ch == '\r' || ch == '\n') {
421
					org_cherry_error(context, "Unexpected newline/carriage return found in string literal");
Chris Müller's avatar
Chris Müller committed
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
					state = STR_FINAL;
					goto RETURN_TOKEN;
				}
				break;

			case STR_ESCAPE:
				switch(ch) {
					case 'a': case 'b': case 'f': case 'n': case 'r':
					case 't': case 'v': case '0': case '\"':
					case '\\':
						state = STR_EAT;
						break;
					case 'u':
						unicount = 4;
						state = STR_UNICODE;
						break;
					case 'U':
						unicount = 6;
						state = STR_UNICODE;
						break;
					default:
443
						org_cherry_error(context, "Unknown escape sequence found in this string literal");
Chris Müller's avatar
Chris Müller committed
444
						state = STR_EAT;
445
						org_cherry_array_append(buffer, "t", 1);
Chris Müller's avatar
Chris Müller committed
446
447
448
449
450
451
452
453
454
455
						goto NO_BUFFER_APPEND;

				}
				break;

			case STR_UNICODE:
				if(--unicount == 0)
					state = STR_EAT;

				if(('0' > ch || ch > '9') && ('A' > ch || ch > 'F')) {
456
					org_cherry_error(context, "Unexpected hex number in unicode escape sequence found");
457
					org_cherry_array_append(buffer, "0", 1);
Chris Müller's avatar
Chris Müller committed
458
459
460
461
462
463
464
465
					goto NO_BUFFER_APPEND;
				}
				break;

			case STR_FINAL:
				goto RETURN_TOKEN;
		}

466
		org_cherry_array_append(buffer, p, org_cherry_utf8_codepoints(p));
Chris Müller's avatar
Chris Müller committed
467
468

NO_BUFFER_APPEND:
469
470
		p = org_cherry_utf8_next(p);
		ch = org_cherry_utf8_get(p);
Chris Müller's avatar
Chris Müller committed
471
472
473
474
	}

RETURN_TOKEN:
	if(state != STR_FINAL) {
475
		org_cherry_error(context, "Unexpected end of file found in unclosed string");
Chris Müller's avatar
Chris Müller committed
476
477

		while(unicount-- > 0)
478
			org_cherry_array_append(buffer, "0", 1);
Chris Müller's avatar
Chris Müller committed
479
480

		if(state == STR_ESCAPE)
481
			org_cherry_array_append(buffer, "0", 1);
Chris Müller's avatar
Chris Müller committed
482
483
484
485
	}

	context->src = p;

486
	org_cherry_array_append(buffer, "\0", 1);
Chris Müller's avatar
Chris Müller committed
487
488
489
490
491

	return TOK_STRING;
}


492
493
static enum org_cherry_tok
lex_comment(struct org_cherry_context* context)
Chris Müller's avatar
Chris Müller committed
494
{
495
	struct org_cherry_array* buffer = context->buffer;
496
497
	const cy_byte_t* p = context->src;
	cy_unicode_t ch = org_cherry_utf8_get(p);
Chris Müller's avatar
Chris Müller committed
498
499

	while(ch != '\0' && ch != '\r' && ch != '\n') {
500
		org_cherry_array_append(buffer, p, org_cherry_utf8_codepoints(p));
Chris Müller's avatar
Chris Müller committed
501

502
503
		p = org_cherry_utf8_next(p);
		ch = org_cherry_utf8_get(p);
Chris Müller's avatar
Chris Müller committed
504
505
	}

506
	org_cherry_array_append(buffer, "\0", 1);
Chris Müller's avatar
Chris Müller committed
507

508
509
	context->src = p;

Chris Müller's avatar
Chris Müller committed
510
511
512
513
514
	return TOK_COMMENT;
}


static int 
515
is_symbol_character(cy_unicode_t ch)
Chris Müller's avatar
Chris Müller committed
516
{
517
	return org_cherry_unicode_isalnum(ch) || 
Chris Müller's avatar
Chris Müller committed
518
519
520
521
522
		ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '%' ||
		ch == '<' || ch == '>' || ch == '=' || ch == '!' || ch == '?' ||
		ch == '#' || ch == ':' || ch == '.' || ch == '~' || ch == '_';
}

523
524
static enum org_cherry_tok
lex_symbol(struct org_cherry_context* context)
Chris Müller's avatar
Chris Müller committed
525
{
526
	struct org_cherry_array* buffer = context->buffer;
527
528
	const cy_byte_t* p = context->src;
	cy_unicode_t ch = org_cherry_utf8_get(p);
Chris Müller's avatar
Chris Müller committed
529
530

	while(is_symbol_character(ch)) {
531
		org_cherry_array_append(buffer, p, org_cherry_utf8_codepoints(p));
Chris Müller's avatar
Chris Müller committed
532

533
534
		p = org_cherry_utf8_next(p);
		ch = org_cherry_utf8_get(p);
Chris Müller's avatar
Chris Müller committed
535
536
537
538
	}

	context->src = p;

539
	org_cherry_array_append(buffer, "\0", 1);
Chris Müller's avatar
Chris Müller committed
540

541
	cy_byte_t* sym = org_cherry_array_get(buffer, 0);
Chris Müller's avatar
Chris Müller committed
542
543
544
545
546
547
548
549
550

	if (strcmp(sym, "true") == 0)
		return TOK_TRUE;
	else if(strcmp(sym, "false") == 0)
		return TOK_FALSE;
	else
		return TOK_SYMBOL;
}

551
#define LEX_RETURN(tok) \
552
    p = org_cherry_utf8_next(p); \
553
554
555
556
    context->src = p; \
    return tok;
    

557
558
enum org_cherry_tok      
org_cherry_lex(struct org_cherry_context* context)
559
560
561
{
	assert(context != 0);

Chris Müller's avatar
Chris Müller committed
562
	while(TRUE) {
563
		const cy_byte_t* p = context->src;
564

565
		org_cherry_array_clear(context->buffer);
566

567
		cy_unicode_t ch = org_cherry_utf8_get(p);
568
		
569
570
		if(org_cherry_unicode_isspace(ch)) {
			p = org_cherry_utf8_next(p);
571
572
573
574
575
576
577
578
			context->src = p;
			continue;
		}

		switch(ch) {
			case '\0':
				return TOK_EOF;
			case '(':
579
				LEX_RETURN(TOK_ROUNDLEFTBRACE);
580
			case ')':
581
				LEX_RETURN(TOK_ROUNDRIGHTBRACE);
582
			case '[':
583
				LEX_RETURN(TOK_SQUARELEFTBRACE);
584
			case ']':
585
				LEX_RETURN(TOK_SQUARERIGHTBRACE);
586
			case '.':
587
588
589
590
				LEX_RETURN(TOK_DOT);
			case '\'':
				LEX_RETURN(TOK_QUOTE);
			case ';':
591
592
593
594
				if(context->flags & CY_SUPRESS_COMMENTS) {
					lex_comment(context);
					continue;
				}
595
596
				return lex_comment(context);
	    	case '0': case '1': case '2': case '3': case '4':
597
598
599
			case '5': case '6': case '7': case '8': case '9':
				return lex_number(context);
			case '\\':
Chris Müller's avatar
Chris Müller committed
600
601
602
603
604
605
606
607
				return lex_character(context);
			case '"':
				return lex_string(context);
			case '+': case '-': case '*': case '/': case '^':
			case '<': case '>': case '=': case '?': case '!':
			case ':': case '_': case '%': case '~': case '#':
				return lex_symbol(context);
			default:
608
				if(org_cherry_unicode_isalpha(ch))
Chris Müller's avatar
Chris Müller committed
609
610
					return lex_symbol(context);
				else {
611
612
					org_cherry_error(context, "Unknown character found in input scanning");
					p = org_cherry_utf8_next(p);
Chris Müller's avatar
Chris Müller committed
613
				}
614
615
616
617
618
619
		}
	}

	return TOK_EOF;
}

620
const cy_byte_t*               
621
622
623
624
625
626
627
org_cherry_pos(struct org_cherry_context* context)
{
	assert(context != 0);
	return context->src;
}

void                        
628
org_cherry_rewind(struct org_cherry_context* context, const cy_byte_t* pos)
629
630
{
	assert(context != 0);
631
	assert(context->begin <= pos && pos <= context->src);
632
633
634
635
636

	context->src = pos;
}


637
const cy_byte_t*
638
org_cherry_token_string(struct org_cherry_context* context)
639
640
641
{
	assert(context->buffer != 0);

642
	return (const cy_byte_t*) org_cherry_array_get(context->buffer, 0);
643
644
645
646
}


size_t
647
org_cherry_token_length(struct org_cherry_context* context)
648
649
650
{
	assert(context->buffer != 0);

651
	return org_cherry_array_size(context->buffer);
652
}
653

654

655
656
657
static struct org_cherry_value*
org_cherry_read_pair(struct org_cherry_context* context)
{
658
	const cy_byte_t* pos;
659
660
661
662
663
664
	enum org_cherry_tok tok;
	struct org_cherry_value* head;
	struct org_cherry_value* tail;
	
	pos = org_cherry_pos(context);
	tok = org_cherry_lex(context);
665

666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
	if(tok == TOK_ROUNDRIGHTBRACE)
		return org_cherry_emptylist;

	org_cherry_rewind(context, pos);

	head = org_cherry_read(context);

	pos = org_cherry_pos(context);
	tok = org_cherry_lex(context);

	if(tok == TOK_DOT) {
		tail = org_cherry_read(context);
		
		if(org_cherry_lex(context) != TOK_ROUNDRIGHTBRACE) {
			org_cherry_error(context, "No trailing right parenthesis in improper list literal");
		}
		return (struct org_cherry_value*) org_cherry_list_cons(head, tail);
	} 
	
	org_cherry_rewind(context, pos);
	tail = org_cherry_read_pair(context);

	return (struct org_cherry_value*) org_cherry_list_cons(head, tail);
689
690
}

691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
struct org_cherry_value*
org_cherry_read(struct org_cherry_context* context)
{
	assert(context != 0);

	enum org_cherry_tok tok = org_cherry_lex(context);

	while(tok != TOK_EOF) {
		switch(tok) {
			case TOK_TRUE:
				return org_cherry_true;
			case TOK_FALSE:
				return org_cherry_false;
			case TOK_HEX:
				return org_cherry_fixnum_from_string(org_cherry_token_string(context), 16);
			case TOK_DEC:
				return org_cherry_fixnum_from_string(org_cherry_token_string(context), 10);
			case TOK_OCT:
				return org_cherry_fixnum_from_string(org_cherry_token_string(context), 8);
			case TOK_BIN:
				return org_cherry_fixnum_from_string(org_cherry_token_string(context), 2);
			case TOK_FLOAT:
				return org_cherry_float_from_string(org_cherry_token_string(context));
			case TOK_STRING:
				return org_cherry_string_from_string(org_cherry_token_string(context));
716
717
718
719
720
            case TOK_CHAR:
                return org_cherry_char_from_string(org_cherry_token_string(context));
            case TOK_SYMBOL:
                return org_cherry_symbol_from_string(org_cherry_token_string(context));
            case TOK_ROUNDLEFTBRACE:
721
				return org_cherry_read_pair(context);
722
723
724
			case TOK_QUOTE:
				return TO_VALUE(org_cherry_list_cons(org_cherry_symbol_quote, 
                        TO_VALUE(org_cherry_list_cons(org_cherry_read(context), org_cherry_emptylist))));
725
726
727
728
729
730
731
732
733
734

			default:
				org_cherry_error(context, "bad input with token %s", 
						org_cherry_tok_to_string(tok));
				return org_cherry_false;
		}
	}

	return org_cherry_false;
}