~ubuntu-branches/ubuntu/hardy/sigscheme/hardy-proposed

« back to all changes in this revision

Viewing changes to read.c

  • Committer: Bazaar Package Importer
  • Author(s): NIIBE Yutaka
  • Date: 2006-05-23 21:46:41 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20060523214641-6ix4gz34wpiehub8
Tags: 0.5.0-2
* debian/control (Build-Depends): Added ruby.
  Thanks to Frederik Schueler.  Closes: #368571
* debian/rules (clean): invoke 'distclean' instead of 'clean'.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*===========================================================================
2
 
 *  FileName : read.c
3
 
 *  About    : S-Expression reader
4
 
 *
5
 
 *  Copyright (C) 2000-2001 by Shiro Kawai (shiro@acm.org)
6
 
 *  Copyright (C) 2005      by Kazuki Ohta (mover@hct.zaq.ne.jp)
7
 
 *
8
 
 *  All rights reserved.
9
 
 *
10
 
 *  Redistribution and use in source and binary forms, with or without
11
 
 *  modification, are permitted provided that the following conditions
12
 
 *  are met:
13
 
 *
14
 
 *  1. Redistributions of source code must retain the above copyright
15
 
 *     notice, this list of conditions and the following disclaimer.
16
 
 *  2. Redistributions in binary form must reproduce the above copyright
17
 
 *     notice, this list of conditions and the following disclaimer in the
18
 
 *     documentation and/or other materials provided with the distribution.
19
 
 *  3. Neither the name of authors nor the names of its contributors
20
 
 *     may be used to endorse or promote products derived from this software
21
 
 *     without specific prior written permission.
22
 
 *
23
 
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
24
 
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25
 
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26
 
 *  ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
27
 
 *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28
 
 *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
29
 
 *  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30
 
 *  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31
 
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32
 
 *  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33
 
 *  SUCH DAMAGE.
34
 
===========================================================================*/
35
 
/*
36
 
 * FIXME: Large fixed-size buffer on stack without limit checking
37
 
 *
38
 
 * Fix some functions contained in this file since:
39
 
 *
40
 
 * - danger
41
 
 * - some embedded platform cannot allocate such large stack (approx. 20KB)
42
 
 * - inefficient from the viewpoint of memory locality (cache, page, power
43
 
 *   consumption etc)
44
 
 *
45
 
 * Search "FIXME" on this file to locate the codes. I wonder other Scheme
46
 
 * implementations may have sophisticated code. Please consider porting them to
47
 
 * save development cost, since this part is not the primary value of
48
 
 * SigScheme.  -- YamaKen 2005-09-05
49
 
 */
50
 
 
51
 
/*
52
 
 * FIXME: Parse properly as defined in "7.1.1 Lexical structure" of R5RS, and
53
 
 * use the popular words for parser as used in R5RS, such as 'token'.
54
 
 */
55
 
 
56
 
/*=======================================
57
 
  System Include
58
 
=======================================*/
59
 
#include <ctype.h>
60
 
#include <stdlib.h>
61
 
#include <string.h>
62
 
 
63
 
/*=======================================
64
 
  Local Include
65
 
=======================================*/
66
 
#include "sigscheme.h"
67
 
#include "sigschemeinternal.h"
68
 
 
69
 
/*=======================================
70
 
  File Local Struct Declarations
71
 
=======================================*/
72
 
 
73
 
/*=======================================
74
 
  File Local Macro Declarations
75
 
=======================================*/
76
 
/* Compatible with isspace(3). Use this to prevent incorrect space handlings */
77
 
#define CASE_ISSPACE                                                         \
78
 
    case ' ': case '\t': case '\n': case '\r': case '\v': case '\f'
79
 
 
80
 
/*=======================================
81
 
  Variable Declarations
82
 
=======================================*/
83
 
 
84
 
/*=======================================
85
 
  File Local Function Declarations
86
 
=======================================*/
87
 
static int    skip_comment_and_space(ScmObj port);
88
 
static char*  read_word(ScmObj port);
89
 
static char*  read_char_sequence(ScmObj port);
90
 
 
91
 
static ScmObj read_sexpression(ScmObj port);
92
 
static ScmObj read_list(ScmObj port, int closeParen);
93
 
static ScmObj read_char(ScmObj port);
94
 
static ScmObj read_string(ScmObj port);
95
 
static ScmObj read_symbol(ScmObj port);
96
 
static ScmObj parse_number(ScmObj port);
97
 
static ScmObj read_number_or_symbol(ScmObj port);
98
 
static ScmObj read_quote(ScmObj port, ScmObj quoter);
99
 
 
100
 
/*=======================================
101
 
  Function Implementations
102
 
=======================================*/
103
 
/*===========================================================================
104
 
  S-Expression Parser
105
 
===========================================================================*/
106
 
ScmObj SigScm_Read(ScmObj port)
107
 
{
108
 
    ScmObj sexp = SCM_FALSE;
109
 
    DECLARE_INTERNAL_FUNCTION("SigScm_Read");
110
 
 
111
 
    ASSERT_PORTP(port);
112
 
 
113
 
    sexp = read_sexpression(port);
114
 
#if SCM_DEBUG
115
 
    if ((SigScm_DebugCategories() & SCM_DBG_READ) && !EOFP(sexp)) {
116
 
        SigScm_WriteToPort(scm_current_error_port, sexp);
117
 
        SigScm_ErrorNewline();
118
 
    }
119
 
#endif
120
 
 
121
 
    return sexp;
122
 
}
123
 
 
124
 
ScmObj SigScm_Read_Char(ScmObj port)
125
 
{
126
 
    DECLARE_INTERNAL_FUNCTION("SigScm_Read_Char");
127
 
 
128
 
    ASSERT_PORTP(port);
129
 
 
130
 
    return read_char(port);
131
 
}
132
 
 
133
 
 
134
 
static int skip_comment_and_space(ScmObj port)
135
 
{
136
 
    int c = 0;
137
 
    while (1) {
138
 
        SCM_PORT_GETC(port, c);
139
 
        if (c == EOF) {
140
 
            return c;
141
 
        } else if(c == ';') {
142
 
            while (1) {
143
 
                SCM_PORT_GETC(port, c);
144
 
                if (c == '\n' || c == '\r') {
145
 
                    break;
146
 
                }
147
 
                if (c == EOF) return c;
148
 
            }
149
 
            continue;
150
 
        } else if(isspace(c)) {
151
 
            continue;
152
 
        }
153
 
 
154
 
        return c;
155
 
    }
156
 
}
157
 
 
158
 
static ScmObj read_sexpression(ScmObj port)
159
 
{
160
 
    int c  = 0;
161
 
    int c1 = 0;
162
 
 
163
 
    CDBG((SCM_DBG_PARSER, "read_sexpression"));
164
 
 
165
 
    while (1) {
166
 
        c = skip_comment_and_space(port);
167
 
 
168
 
        CDBG((SCM_DBG_PARSER, "read_sexpression c = %c", c));
169
 
 
170
 
        switch (c) {
171
 
        case '(':
172
 
            return read_list(port, ')');
173
 
        case '\"':
174
 
            return read_string(port);
175
 
        case '0': case '1': case '2': case '3': case '4':
176
 
        case '5': case '6': case '7': case '8': case '9':
177
 
        case '+': case '-':
178
 
            SCM_PORT_UNGETC(port, c);
179
 
            return read_number_or_symbol(port);
180
 
        case '\'':
181
 
            return read_quote(port, SCM_QUOTE);
182
 
        case '`':
183
 
            return read_quote(port, SCM_QUASIQUOTE);
184
 
        case ',':
185
 
            SCM_PORT_GETC(port, c1);
186
 
            if (c1 == EOF) {
187
 
                SigScm_Error("EOF in unquote");
188
 
            } else if (c1 == '@') {
189
 
                return read_quote(port, SCM_UNQUOTE_SPLICING);
190
 
            } else {
191
 
                SCM_PORT_UNGETC(port, c1);
192
 
                return read_quote(port, SCM_UNQUOTE);
193
 
            }
194
 
            break;
195
 
        case '#':
196
 
            SCM_PORT_GETC(port, c1);
197
 
            switch (c1) {
198
 
            case 't': case 'T':
199
 
                return SCM_TRUE;
200
 
            case 'f': case 'F':
201
 
                return SCM_FALSE;
202
 
            case '(':
203
 
                return ScmOp_list2vector(read_list(port, ')'));
204
 
            case '\\':
205
 
                return read_char(port);
206
 
            case 'b': case 'o': case 'd': case 'x':
207
 
                SCM_PORT_UNGETC(port, c1);
208
 
                return parse_number(port);
209
 
            case EOF:
210
 
                SigScm_Error("end in #");
211
 
            default:
212
 
                SigScm_Error("Unsupported # : %c", c1);
213
 
            }
214
 
            break;
215
 
        /* Error sequence */
216
 
        case ')':
217
 
            SigScm_Error("invalid close parenthesis");
218
 
            break;
219
 
        case EOF:
220
 
            return SCM_EOF;
221
 
        default:
222
 
            SCM_PORT_UNGETC(port, c);
223
 
            return read_symbol(port);
224
 
        }
225
 
    }
226
 
}
227
 
 
228
 
static ScmObj read_list(ScmObj port, int closeParen)
229
 
{
230
 
    ScmObj list_head = SCM_NULL;
231
 
    ScmObj list_tail = SCM_NULL;
232
 
    ScmObj item   = SCM_NULL;
233
 
    ScmObj cdr    = SCM_NULL;
234
 
    int    line   = SCM_PORT_LINE(port);
235
 
    int    c      = 0;
236
 
    int    c2     = 0;
237
 
    char  *token  = NULL;
238
 
 
239
 
    CDBG((SCM_DBG_PARSER, "read_list"));
240
 
 
241
 
    while (1) {
242
 
        c = skip_comment_and_space(port);
243
 
 
244
 
        CDBG((SCM_DBG_PARSER, "read_list c = [%c]", c));
245
 
 
246
 
        if (c == EOF) {
247
 
            if (SCM_PORT_PORTTYPE(port) == PORT_FILE)
248
 
                SigScm_Error("EOF inside list. (starting from line %d)", line + 1);
249
 
            else
250
 
                SigScm_Error("EOF inside list.");
251
 
        } else if (c == closeParen) {
252
 
            return list_head;
253
 
        } else if (c == '.') {
254
 
            c2 = 0;
255
 
            SCM_PORT_GETC(port, c2);
256
 
            CDBG((SCM_DBG_PARSER, "read_list process_dot c2 = [%c]", c2));
257
 
            if (isspace(c2) || c2 == '(' || c2 == '"' || c2 == ';') {
258
 
                cdr = read_sexpression(port);
259
 
                if (NULLP(list_tail))
260
 
                    SigScm_Error(".(dot) at the start of the list.");
261
 
 
262
 
                c = skip_comment_and_space(port);
263
 
                if (c != ')')
264
 
                    SigScm_Error("bad dot syntax");
265
 
 
266
 
                SET_CDR(list_tail, cdr);
267
 
                return list_head;
268
 
            }
269
 
 
270
 
            /*
271
 
             * This dirty hack here picks up the current token as a
272
 
             * symbol beginning with the dot (that's how Guile and
273
 
             * Gauche behave).
274
 
             */
275
 
            SCM_PORT_UNGETC(port, c2);
276
 
            token = read_word(port);
277
 
            token = (char*)realloc(token, strlen(token) + 1 + 1);
278
 
            memmove(token + 1, token, strlen(token)+1);
279
 
            token[0] = '.';
280
 
            item = Scm_Intern(token);
281
 
            free(token);
282
 
        } else {
283
 
            SCM_PORT_UNGETC(port, c);
284
 
            item = read_sexpression(port);
285
 
        }
286
 
 
287
 
        /* Append item to the list_tail. */
288
 
        if (NULLP(list_tail)) {
289
 
            /* create new list */
290
 
            list_head = CONS(item, SCM_NULL);
291
 
            list_tail = list_head;
292
 
        } else {
293
 
            /* update list_tail */
294
 
            SET_CDR(list_tail, CONS(item, SCM_NULL));
295
 
            list_tail = CDR(list_tail);
296
 
        }
297
 
    }
298
 
}
299
 
 
300
 
static ScmObj read_char(ScmObj port)
301
 
{
302
 
    char *ch = read_char_sequence(port);
303
 
 
304
 
    CDBG((SCM_DBG_PARSER, "read_char : ch = %s", ch));
305
 
 
306
 
    /* FIXME: Simplify with Scm_special_char_table */
307
 
    /* check special sequence "space" and "newline" */
308
 
    if (strcmp(ch, "space") == 0) {
309
 
        ch[0] = ' ';
310
 
        ch[1] = '\0';
311
 
#if 0
312
 
    /* to avoid portability problem, we should not support #\Space and so on */
313
 
    } else if (strcmp(ch, "Space") == 0) {
314
 
        ch[0] = ' ';
315
 
        ch[1] = '\0';
316
 
#endif
317
 
    } else if (strcmp(ch, "newline") == 0) {
318
 
        /* TODO: Support platform-dependent newline character sequence */
319
 
        ch[0] = '\n';
320
 
        ch[1] = '\0';
321
 
    }
322
 
 
323
 
    /* FIXME: memory leak */
324
 
    return Scm_NewChar(ch);
325
 
}
326
 
 
327
 
static ScmObj read_string(ScmObj port)
328
 
{
329
 
    char  stringbuf[1024]; /* FIXME! */
330
 
    int   stringlen = 0;
331
 
    int   c = 0;
332
 
 
333
 
    CDBG((SCM_DBG_PARSER, "read_string"));
334
 
 
335
 
    while (1) {
336
 
        SCM_PORT_GETC(port, c);
337
 
 
338
 
        CDBG((SCM_DBG_PARSER, "read_string c = %c", c));
339
 
 
340
 
        switch (c) {
341
 
        case EOF:
342
 
            stringbuf[stringlen] = '\0';
343
 
            SigScm_Error("EOF in the string : str = %s", stringbuf);
344
 
            break;
345
 
 
346
 
        case '\"':
347
 
            stringbuf[stringlen] = '\0';
348
 
            return Scm_NewStringCopying(stringbuf);
349
 
 
350
 
        case '\\':
351
 
            /* FIXME: Simplify with Scm_special_char_table */
352
 
            /*
353
 
             * (R5RS) 6.3.5 String
354
 
             * A double quote can be written inside a string only by
355
 
             * escaping it with a backslash (\).
356
 
             */
357
 
            SCM_PORT_GETC(port, c);
358
 
            switch (c) {
359
 
            case '\"': stringbuf[stringlen] = c;    break;
360
 
            case 'n':  stringbuf[stringlen] = '\n'; break;
361
 
            case 'r':  stringbuf[stringlen] = '\r'; break;
362
 
            case 'f':  stringbuf[stringlen] = '\f'; break;
363
 
            case 't':  stringbuf[stringlen] = '\t'; break;
364
 
            case '\\': stringbuf[stringlen] = '\\'; break;
365
 
            default:
366
 
                stringbuf[stringlen] = '\\';
367
 
                stringbuf[++stringlen] = c;
368
 
                break;
369
 
            }
370
 
            stringlen++;
371
 
            break;
372
 
 
373
 
        default:
374
 
            stringbuf[stringlen] = c;
375
 
            stringlen++;
376
 
            break;
377
 
        }
378
 
    }
379
 
}
380
 
 
381
 
static ScmObj read_symbol(ScmObj port)
382
 
{
383
 
    char  *sym_name = read_word(port);
384
 
    ScmObj sym = Scm_Intern(sym_name);
385
 
    free(sym_name);
386
 
 
387
 
    CDBG((SCM_DBG_PARSER, "read_symbol"));
388
 
 
389
 
    return sym;
390
 
}
391
 
 
392
 
/*
393
 
 * FIXME: Parse properly as defined in "7.1.1 Lexical structure" of R5RS. For
394
 
 * example, 1+ is not a valid identifier and should be rejected to prevent
395
 
 * introducing unintended R5RS-incompatibility.
396
 
 */
397
 
static ScmObj read_number_or_symbol(ScmObj port)
398
 
{
399
 
    int number = 0;
400
 
    int str_len = 0;
401
 
    char *str = NULL;
402
 
    char *first_nondigit = NULL;
403
 
    ScmObj ret = SCM_NULL;
404
 
 
405
 
    CDBG((SCM_DBG_PARSER, "read_number_or_symbol"));
406
 
 
407
 
    /* read char sequence */
408
 
    str = read_word(port);
409
 
    str_len = strlen(str);
410
 
 
411
 
    /* see if it's a decimal integer */
412
 
    number = (int)strtol(str, &first_nondigit, 10);
413
 
 
414
 
    /* set return obj */
415
 
    ret = (*first_nondigit) ? Scm_Intern(str) : Scm_NewInt(number);
416
 
 
417
 
    /* free */
418
 
    free(str);
419
 
 
420
 
    return ret;
421
 
}
422
 
 
423
 
 
424
 
static char *read_word(ScmObj port)
425
 
{
426
 
    char  stringbuf[1024];  /* FIXME! */
427
 
    int   stringlen = 0;
428
 
    int   c = 0;
429
 
    char *dst = NULL;
430
 
 
431
 
    while (1) {
432
 
        SCM_PORT_GETC(port, c);
433
 
 
434
 
        CDBG((SCM_DBG_PARSER, "c = %c", c));
435
 
 
436
 
        switch (c) {
437
 
        case EOF: /* don't became an error for handling c-eval, like Scm_eval_c_string("some-symbol"); */
438
 
        case '(': case ')': case '\"': case '\'': case ';':
439
 
        CASE_ISSPACE:
440
 
            SCM_PORT_UNGETC(port, c);
441
 
            stringbuf[stringlen] = '\0';
442
 
            dst = strdup(stringbuf);
443
 
            return dst;
444
 
 
445
 
        default:
446
 
            stringbuf[stringlen++] = (char)c;
447
 
            break;
448
 
        }
449
 
    }
450
 
}
451
 
 
452
 
static char *read_char_sequence(ScmObj port)
453
 
{
454
 
    char  stringbuf[1024];  /* FIXME! */
455
 
    int   stringlen = 0;
456
 
    int   c = 0;
457
 
    char *dst = NULL;
458
 
 
459
 
    while (1) {
460
 
        SCM_PORT_GETC(port, c);
461
 
 
462
 
        CDBG((SCM_DBG_PARSER, "c = %c", c));
463
 
 
464
 
        switch (c) {
465
 
        case EOF:
466
 
            stringbuf[stringlen] = '\0';
467
 
            SigScm_Error("EOF in the char sequence : char = %s", stringbuf);
468
 
            break;
469
 
 
470
 
        case '(': case ')': case '\"': case '\'': case ';':
471
 
        CASE_ISSPACE:
472
 
            /* pass through first char */
473
 
            if (stringlen == 0) {
474
 
                stringbuf[stringlen++] = (char)c;
475
 
                break;
476
 
            }
477
 
            /* return buf */
478
 
            SCM_PORT_UNGETC(port, c);
479
 
            stringbuf[stringlen] = '\0';
480
 
            dst = strdup(stringbuf);
481
 
            return dst;
482
 
 
483
 
        default:
484
 
            stringbuf[stringlen++] = (char)c;
485
 
            break;
486
 
        }
487
 
    }
488
 
}
489
 
 
490
 
static ScmObj read_quote(ScmObj port, ScmObj quoter)
491
 
{
492
 
    return SCM_LIST_2(quoter, read_sexpression(port));
493
 
}
494
 
 
495
 
/* str should be what appeared right after '#' (eg. #b123) */
496
 
static ScmObj parse_number(ScmObj port)
497
 
{
498
 
    int radix  = 0;
499
 
    int number = 0;
500
 
    char *first_nondigit = NULL;
501
 
    char *numstr = read_word(port);
502
 
 
503
 
    switch (numstr[0]) {
504
 
    case 'b': radix = 2;  break;
505
 
    case 'o': radix = 8;  break;
506
 
    case 'd': radix = 10; break;
507
 
    case 'x': radix = 16; break;
508
 
    default:
509
 
        SigScm_Error("ill-formatted number: #%s", numstr);
510
 
    }
511
 
 
512
 
    /* get num */
513
 
    number = (int)strtol(numstr+1, &first_nondigit, radix);
514
 
    if (*first_nondigit)
515
 
        SigScm_Error("ill-formatted number: #%s", numstr);
516
 
 
517
 
    /* free str */
518
 
    free(numstr);
519
 
 
520
 
    return Scm_NewInt(number);
521
 
}