255 lines
4.7 KiB
C
255 lines
4.7 KiB
C
/**
|
|
* See Copyright Notice in picrin.h
|
|
*/
|
|
|
|
#include "picrin.h"
|
|
#include "picrin/parse.h"
|
|
#include "picrin/pair.h"
|
|
#include "picrin/string.h"
|
|
#include "picrin/vector.h"
|
|
#include "picrin/blob.h"
|
|
#include "picrin/port.h"
|
|
|
|
#define YY_NO_UNISTD_H
|
|
#include "lex.yy.h"
|
|
|
|
static pic_value read(int, yyscan_t);
|
|
|
|
#define pic (yyget_extra(scanner)->pic)
|
|
#define yylval (yyget_extra(scanner)->yylval)
|
|
#define yymsg (yyget_extra(scanner)->msg)
|
|
#define yyjmp (yyget_extra(scanner)->jmp)
|
|
|
|
static void
|
|
error(const char *msg, yyscan_t scanner)
|
|
{
|
|
yymsg = msg;
|
|
longjmp(yyjmp, 1);
|
|
}
|
|
|
|
static int
|
|
gettok(yyscan_t scanner)
|
|
{
|
|
int tok;
|
|
|
|
while ((tok = yylex(scanner)) == tDATUM_COMMENT) {
|
|
read(gettok(scanner), scanner); /* discard */
|
|
}
|
|
return tok;
|
|
}
|
|
|
|
static pic_value
|
|
read_pair(int tOPEN, yyscan_t scanner)
|
|
{
|
|
int tok, tCLOSE = (tOPEN == tLPAREN) ? tRPAREN : tRBRACKET;
|
|
pic_value car, cdr;
|
|
|
|
tok = gettok(scanner);
|
|
if (tok == tCLOSE) {
|
|
return pic_nil_value();
|
|
}
|
|
if (tok == tDOT) {
|
|
cdr = read(gettok(scanner), scanner);
|
|
|
|
if (gettok(scanner) != tCLOSE) {
|
|
error("unmatched parenthesis", scanner);
|
|
}
|
|
return cdr;
|
|
}
|
|
else {
|
|
car = read(tok, scanner);
|
|
cdr = read_pair(tOPEN, scanner);
|
|
return pic_cons(pic, car, cdr);
|
|
}
|
|
}
|
|
|
|
static pic_vec *
|
|
read_vect(yyscan_t scanner)
|
|
{
|
|
int tok;
|
|
pic_value val;
|
|
|
|
val = pic_nil_value();
|
|
while ((tok = gettok(scanner)) != tRPAREN) {
|
|
val = pic_cons(pic, read(tok, scanner), val);
|
|
}
|
|
return pic_vec_new_from_list(pic, pic_reverse(pic, val));
|
|
}
|
|
|
|
static pic_value
|
|
read_abbrev(pic_sym sym, yyscan_t scanner)
|
|
{
|
|
return pic_cons(pic, pic_sym_value(sym), pic_cons(pic, read(gettok(scanner), scanner), pic_nil_value()));
|
|
}
|
|
|
|
static pic_value
|
|
read_datum(int tok, yyscan_t scanner)
|
|
{
|
|
pic_value val;
|
|
|
|
switch (tok) {
|
|
case tSYMBOL:
|
|
return pic_symbol_value(pic_intern(pic, yylval.buf.dat, yylval.buf.len));
|
|
|
|
case tINT:
|
|
return pic_int_value(yylval.i);
|
|
|
|
case tFLOAT:
|
|
return pic_float_value(yylval.f);
|
|
|
|
case tBOOLEAN:
|
|
return pic_bool_value(yylval.i);
|
|
|
|
case tCHAR:
|
|
return pic_char_value(yylval.c);
|
|
|
|
case tSTRING:
|
|
val = pic_obj_value(pic_str_new(pic, yylval.buf.dat, yylval.buf.len));
|
|
pic_free(pic, yylval.buf.dat);
|
|
return val;
|
|
|
|
case tBYTEVECTOR:
|
|
val = pic_obj_value(pic_blob_new(pic, yylval.buf.dat, yylval.buf.len));
|
|
pic_free(pic, yylval.buf.dat);
|
|
return val;
|
|
|
|
case tLPAREN:
|
|
case tLBRACKET:
|
|
return read_pair(tok, scanner);
|
|
|
|
case tVPAREN:
|
|
return pic_obj_value(read_vect(scanner));
|
|
|
|
case tQUOTE:
|
|
return read_abbrev(pic->sQUOTE, scanner);
|
|
|
|
case tQUASIQUOTE:
|
|
return read_abbrev(pic->sQUASIQUOTE, scanner);
|
|
|
|
case tUNQUOTE:
|
|
return read_abbrev(pic->sUNQUOTE, scanner);
|
|
|
|
case tUNQUOTE_SPLICING:
|
|
return read_abbrev(pic->sUNQUOTE_SPLICING, scanner);
|
|
|
|
case tRPAREN:
|
|
error("unexpected close parenthesis", scanner);
|
|
|
|
case tRBRACKET:
|
|
error("unexpected close bracket", scanner);
|
|
|
|
case tDOT:
|
|
error("unexpected '.'", scanner);
|
|
|
|
case tEOF:
|
|
error(NULL, scanner);
|
|
}
|
|
|
|
/* unreachable */
|
|
return pic_undef_value();
|
|
}
|
|
|
|
static pic_value
|
|
read(int tok, yyscan_t scanner)
|
|
{
|
|
int ai = pic_gc_arena_preserve(pic);
|
|
pic_value val;
|
|
|
|
val = read_datum(tok, scanner);
|
|
|
|
pic_gc_arena_restore(pic, ai);
|
|
pic_gc_protect(pic, val);
|
|
return val;
|
|
}
|
|
|
|
pic_value
|
|
read_one(yyscan_t scanner)
|
|
{
|
|
int tok;
|
|
|
|
if (setjmp(yyjmp) != 0) {
|
|
pic_errorf(pic, "%s", yymsg ? yymsg : "unexpected EOF");
|
|
}
|
|
|
|
if ((tok = gettok(scanner)) == tEOF) {
|
|
return pic_undef_value();
|
|
}
|
|
return read(tok, scanner);
|
|
}
|
|
|
|
pic_list
|
|
read_many(yyscan_t scanner)
|
|
{
|
|
int tok;
|
|
pic_value vals;
|
|
|
|
if (setjmp(yyjmp) != 0) {
|
|
if (yymsg) {
|
|
pic_errorf(pic, "%s", yymsg);
|
|
}
|
|
return pic_undef_value(); /* incomplete string */
|
|
}
|
|
|
|
vals = pic_nil_value();
|
|
while ((tok = gettok(scanner)) != tEOF) {
|
|
vals = pic_cons(pic, read(tok, scanner), vals);
|
|
}
|
|
return pic_reverse(pic, vals);
|
|
}
|
|
|
|
#undef pic
|
|
|
|
pic_value
|
|
pic_read(pic_state *pic, const char *cstr)
|
|
{
|
|
yyscan_t scanner;
|
|
struct parser_control ctrl;
|
|
pic_value val;
|
|
|
|
ctrl.pic = pic;
|
|
yylex_init_extra(&ctrl, &scanner);
|
|
yy_scan_string(cstr, scanner);
|
|
|
|
val = read_one(scanner);
|
|
|
|
yylex_destroy(scanner);
|
|
|
|
return val;
|
|
}
|
|
|
|
pic_list
|
|
pic_parse_file(pic_state *pic, FILE *file)
|
|
{
|
|
yyscan_t scanner;
|
|
struct parser_control ctrl;
|
|
pic_value vals;
|
|
|
|
ctrl.pic = pic;
|
|
yylex_init_extra(&ctrl, &scanner);
|
|
yyset_in(file, scanner);
|
|
|
|
vals = read_many(scanner);
|
|
|
|
yylex_destroy(scanner);
|
|
|
|
return vals;
|
|
}
|
|
|
|
pic_list
|
|
pic_parse_cstr(pic_state *pic, const char *cstr)
|
|
{
|
|
yyscan_t scanner;
|
|
struct parser_control ctrl;
|
|
pic_value vals;
|
|
|
|
ctrl.pic = pic;
|
|
yylex_init_extra(&ctrl, &scanner);
|
|
yy_scan_string(cstr, scanner);
|
|
|
|
vals = read_many(scanner);
|
|
|
|
yylex_destroy(scanner);
|
|
|
|
return vals;
|
|
}
|