qse/ase/lsp/read.c

431 lines
9.7 KiB
C
Raw Normal View History

2005-02-04 15:39:11 +00:00
/*
2006-10-23 14:57:44 +00:00
* $Id: read.c,v 1.19 2006-10-23 14:44:43 bacon Exp $
2005-02-04 15:39:11 +00:00
*/
2006-10-22 13:10:46 +00:00
#include <sse/lsp/lsp.h>
#include <sse/lsp/token.h>
#include <sse/bas/assert.h>
#include <sse/bas/ctype.h>
2005-02-04 15:39:11 +00:00
2006-10-22 13:10:46 +00:00
#define IS_SPACE(x) sse_isspace(x)
#define IS_DIGIT(x) sse_isdigit(x)
#define IS_ALPHA(x) sse_isalpha(x)
#define IS_ALNUM(x) sse_isalnum(x)
2005-02-04 15:39:11 +00:00
#define IS_IDENT(c) \
2006-10-23 14:57:44 +00:00
((c) == SSE_T('+') || (c) == SSE_T('-') || \
(c) == SSE_T('*') || (c) == SSE_T('/') || \
(c) == SSE_T('%') || (c) == SSE_T('&') || \
(c) == SSE_T('<') || (c) == SSE_T('>') || \
(c) == SSE_T('=') || (c) == SSE_T('_') || \
(c) == SSE_T('?'))
2006-10-22 13:10:46 +00:00
#define TOKEN_CLEAR(lsp) sse_lsp_token_clear (&(lsp)->token)
2005-09-18 10:23:19 +00:00
#define TOKEN_TYPE(lsp) (lsp)->token.type
#define TOKEN_IVALUE(lsp) (lsp)->token.ivalue
2005-09-20 11:19:15 +00:00
#define TOKEN_RVALUE(lsp) (lsp)->token.rvalue
2005-09-18 10:23:19 +00:00
#define TOKEN_SVALUE(lsp) (lsp)->token.name.buffer
#define TOKEN_SLENGTH(lsp) (lsp)->token.name.size
2005-11-18 17:58:47 +00:00
#define TOKEN_ADD_CHAR(lsp,ch) do { \
2006-10-22 13:10:46 +00:00
if (sse_lsp_token_addc(&(lsp)->token, ch) == -1) { \
lsp->errnum = SSE_LSP_ERR_MEMORY; \
2005-11-18 17:58:47 +00:00
return -1; \
} \
} while (0)
2006-10-22 13:10:46 +00:00
#define TOKEN_COMPARE(lsp,str) sse_lsp_token_compare_name (&(lsp)->token, str)
2005-02-04 15:39:11 +00:00
#define TOKEN_END 0
#define TOKEN_INT 1
2005-09-20 11:19:15 +00:00
#define TOKEN_REAL 2
2005-02-04 15:39:11 +00:00
#define TOKEN_STRING 3
#define TOKEN_LPAREN 4
#define TOKEN_RPAREN 5
#define TOKEN_IDENT 6
#define TOKEN_QUOTE 7
#define TOKEN_DOT 8
#define TOKEN_INVALID 50
#define TOKEN_UNTERM_STRING 51
#define NEXT_CHAR(lsp) \
2005-09-18 13:06:43 +00:00
do { if (read_char(lsp) == -1) return -1;} while (0)
2005-02-04 15:39:11 +00:00
#define NEXT_TOKEN(lsp) \
2006-10-22 13:10:46 +00:00
do { if (read_token(lsp) == -1) return SSE_NULL; } while (0)
2005-02-04 15:39:11 +00:00
2006-10-22 13:10:46 +00:00
static sse_lsp_obj_t* read_obj (sse_lsp_t* lsp);
static sse_lsp_obj_t* read_list (sse_lsp_t* lsp);
static sse_lsp_obj_t* read_quote (sse_lsp_t* lsp);
2005-09-18 12:20:43 +00:00
2006-10-22 13:10:46 +00:00
static int read_char (sse_lsp_t* lsp);
static int read_token (sse_lsp_t* lsp);
static int read_number (sse_lsp_t* lsp, int negative);
static int read_ident (sse_lsp_t* lsp);
static int read_string (sse_lsp_t* lsp);
2005-09-18 12:20:43 +00:00
2006-10-22 13:10:46 +00:00
sse_lsp_obj_t* sse_lsp_read (sse_lsp_t* lsp)
2005-02-04 15:39:11 +00:00
{
2006-10-23 14:57:44 +00:00
if (lsp->curc == SSE_T_EOF &&
2006-10-22 13:10:46 +00:00
read_char(lsp) == -1) return SSE_NULL;
2005-02-04 15:39:11 +00:00
2006-10-22 13:10:46 +00:00
lsp->errnum = SSE_LSP_ERR_NONE;
2005-02-04 15:39:11 +00:00
NEXT_TOKEN (lsp);
2006-10-22 13:10:46 +00:00
if (lsp->mem->locked != SSE_NULL) {
sse_lsp_unlock_all (lsp->mem->locked);
lsp->mem->locked = SSE_NULL;
2005-02-04 15:39:11 +00:00
}
lsp->mem->locked = read_obj (lsp);
return lsp->mem->locked;
}
2006-10-22 13:10:46 +00:00
static sse_lsp_obj_t* read_obj (sse_lsp_t* lsp)
2005-02-04 15:39:11 +00:00
{
2006-10-22 13:10:46 +00:00
sse_lsp_obj_t* obj;
2005-02-04 15:39:11 +00:00
switch (TOKEN_TYPE(lsp)) {
case TOKEN_END:
2006-10-22 13:10:46 +00:00
lsp->errnum = SSE_LSP_ERR_END;
return SSE_NULL;
2005-02-04 15:39:11 +00:00
case TOKEN_LPAREN:
NEXT_TOKEN (lsp);
return read_list (lsp);
case TOKEN_QUOTE:
NEXT_TOKEN (lsp);
return read_quote (lsp);
case TOKEN_INT:
2006-10-22 13:10:46 +00:00
obj = sse_lsp_make_int (lsp->mem, TOKEN_IVALUE(lsp));
if (obj == SSE_NULL) lsp->errnum = SSE_LSP_ERR_MEMORY;
sse_lsp_lock (obj);
2005-02-04 15:39:11 +00:00
return obj;
2005-09-20 11:19:15 +00:00
case TOKEN_REAL:
2006-10-22 13:10:46 +00:00
obj = sse_lsp_make_real (lsp->mem, TOKEN_RVALUE(lsp));
if (obj == SSE_NULL) lsp->errnum = SSE_LSP_ERR_MEMORY;
sse_lsp_lock (obj);
2005-02-04 15:39:11 +00:00
return obj;
case TOKEN_STRING:
2006-10-22 13:10:46 +00:00
obj = sse_lsp_make_stringx (
2005-02-04 15:39:11 +00:00
lsp->mem, TOKEN_SVALUE(lsp), TOKEN_SLENGTH(lsp));
2006-10-22 13:10:46 +00:00
if (obj == SSE_NULL) lsp->errnum = SSE_LSP_ERR_MEMORY;
sse_lsp_lock (obj);
2005-02-04 15:39:11 +00:00
return obj;
case TOKEN_IDENT:
2006-10-22 13:10:46 +00:00
sse_assert (lsp->mem->nil != SSE_NULL && lsp->mem->t != SSE_NULL);
2006-10-23 14:57:44 +00:00
if (TOKEN_COMPARE(lsp,SSE_T("nil")) == 0) obj = lsp->mem->nil;
else if (TOKEN_COMPARE(lsp,SSE_T("t")) == 0) obj = lsp->mem->t;
2005-02-04 15:39:11 +00:00
else {
2006-10-22 13:10:46 +00:00
obj = sse_lsp_make_symbolx (
2005-02-04 15:39:11 +00:00
lsp->mem, TOKEN_SVALUE(lsp), TOKEN_SLENGTH(lsp));
2006-10-22 13:10:46 +00:00
if (obj == SSE_NULL) lsp->errnum = SSE_LSP_ERR_MEMORY;
sse_lsp_lock (obj);
2005-02-04 15:39:11 +00:00
}
return obj;
}
2006-10-22 13:10:46 +00:00
lsp->errnum = SSE_LSP_ERR_SYNTAX;
return SSE_NULL;
2005-02-04 15:39:11 +00:00
}
2006-10-22 13:10:46 +00:00
static sse_lsp_obj_t* read_list (sse_lsp_t* lsp)
2005-02-04 15:39:11 +00:00
{
2006-10-22 13:10:46 +00:00
sse_lsp_obj_t* obj;
sse_lsp_obj_cons_t* p, * first = SSE_NULL, * prev = SSE_NULL;
2005-02-04 15:39:11 +00:00
while (TOKEN_TYPE(lsp) != TOKEN_RPAREN) {
if (TOKEN_TYPE(lsp) == TOKEN_END) {
2006-10-22 13:10:46 +00:00
lsp->errnum = SSE_LSP_ERR_SYNTAX; // unexpected end of input
return SSE_NULL;
2005-02-04 15:39:11 +00:00
}
if (TOKEN_TYPE(lsp) == TOKEN_DOT) {
2006-10-22 13:10:46 +00:00
if (prev == SSE_NULL) {
lsp->errnum = SSE_LSP_ERR_SYNTAX; // unexpected .
return SSE_NULL;
2005-02-04 15:39:11 +00:00
}
NEXT_TOKEN (lsp);
obj = read_obj (lsp);
2006-10-22 13:10:46 +00:00
if (obj == SSE_NULL) {
if (lsp->errnum == SSE_LSP_ERR_END) {
2005-02-04 15:39:11 +00:00
//unexpected end of input
2006-10-22 13:10:46 +00:00
lsp->errnum = SSE_LSP_ERR_SYNTAX;
2005-02-04 15:39:11 +00:00
}
2006-10-22 13:10:46 +00:00
return SSE_NULL;
2005-02-04 15:39:11 +00:00
}
prev->cdr = obj;
NEXT_TOKEN (lsp);
if (TOKEN_TYPE(lsp) != TOKEN_RPAREN) {
2006-10-22 13:10:46 +00:00
lsp->errnum = SSE_LSP_ERR_SYNTAX; // ) expected
return SSE_NULL;
2005-02-04 15:39:11 +00:00
}
break;
}
obj = read_obj (lsp);
2006-10-22 13:10:46 +00:00
if (obj == SSE_NULL) {
if (lsp->errnum == SSE_LSP_ERR_END) {
2005-02-04 15:39:11 +00:00
// unexpected end of input
2006-10-22 13:10:46 +00:00
lsp->errnum = SSE_LSP_ERR_SYNTAX;
2005-02-04 15:39:11 +00:00
}
2006-10-22 13:10:46 +00:00
return SSE_NULL;
2005-02-04 15:39:11 +00:00
}
2006-10-22 13:10:46 +00:00
p = (sse_lsp_obj_cons_t*)sse_lsp_make_cons (
2005-02-04 15:39:11 +00:00
lsp->mem, lsp->mem->nil, lsp->mem->nil);
2006-10-22 13:10:46 +00:00
if (p == SSE_NULL) {
lsp->errnum = SSE_LSP_ERR_MEMORY;
return SSE_NULL;
2005-02-04 15:39:11 +00:00
}
2006-10-22 13:10:46 +00:00
sse_lsp_lock ((sse_lsp_obj_t*)p);
2005-02-04 15:39:11 +00:00
2006-10-22 13:10:46 +00:00
if (first == SSE_NULL) first = p;
if (prev != SSE_NULL) prev->cdr = (sse_lsp_obj_t*)p;
2005-02-04 15:39:11 +00:00
p->car = obj;
prev = p;
NEXT_TOKEN (lsp);
}
2006-10-22 13:10:46 +00:00
return (first == SSE_NULL)? lsp->mem->nil: (sse_lsp_obj_t*)first;
2005-02-04 15:39:11 +00:00
}
2006-10-22 13:10:46 +00:00
static sse_lsp_obj_t* read_quote (sse_lsp_t* lsp)
2005-02-04 15:39:11 +00:00
{
2006-10-22 13:10:46 +00:00
sse_lsp_obj_t* cons, * tmp;
2005-02-04 15:39:11 +00:00
tmp = read_obj (lsp);
2006-10-22 13:10:46 +00:00
if (tmp == SSE_NULL) {
if (lsp->errnum == SSE_LSP_ERR_END) {
2005-02-04 15:39:11 +00:00
// unexpected end of input
2006-10-22 13:10:46 +00:00
lsp->errnum = SSE_LSP_ERR_SYNTAX;
2005-02-04 15:39:11 +00:00
}
2006-10-22 13:10:46 +00:00
return SSE_NULL;
2005-02-04 15:39:11 +00:00
}
2006-10-22 13:10:46 +00:00
cons = sse_lsp_make_cons (lsp->mem, tmp, lsp->mem->nil);
if (cons == SSE_NULL) {
lsp->errnum = SSE_LSP_ERR_MEMORY;
return SSE_NULL;
2005-02-04 15:39:11 +00:00
}
2006-10-22 13:10:46 +00:00
sse_lsp_lock (cons);
2005-02-04 15:39:11 +00:00
2006-10-22 13:10:46 +00:00
cons = sse_lsp_make_cons (lsp->mem, lsp->mem->quote, cons);
if (cons == SSE_NULL) {
lsp->errnum = SSE_LSP_ERR_MEMORY;
return SSE_NULL;
2005-02-04 15:39:11 +00:00
}
2006-10-22 13:10:46 +00:00
sse_lsp_lock (cons);
2005-02-04 15:39:11 +00:00
return cons;
}
2006-10-22 13:10:46 +00:00
static int read_char (sse_lsp_t* lsp)
2005-09-18 13:06:43 +00:00
{
2006-10-22 13:10:46 +00:00
sse_ssize_t n;
2005-09-18 13:06:43 +00:00
2006-10-22 13:10:46 +00:00
if (lsp->input_func == SSE_NULL) {
lsp->errnum = SSE_LSP_ERR_INPUT_NOT_ATTACHED;
2005-09-18 13:06:43 +00:00
return -1;
}
2006-10-22 13:10:46 +00:00
n = lsp->input_func(SSE_LSP_IO_DATA, lsp->input_arg, &lsp->curc, 1);
2005-09-18 13:06:43 +00:00
if (n == -1) {
2006-10-22 13:10:46 +00:00
lsp->errnum = SSE_LSP_ERR_INPUT;
2005-09-18 13:06:43 +00:00
return -1;
}
2006-10-23 14:57:44 +00:00
if (n == 0) lsp->curc = SSE_T_EOF;
2005-09-18 13:06:43 +00:00
return 0;
}
2006-10-22 13:10:46 +00:00
static int read_token (sse_lsp_t* lsp)
2005-02-04 15:39:11 +00:00
{
2006-10-22 13:10:46 +00:00
sse_assert (lsp->input_func != SSE_NULL);
2005-02-04 15:39:11 +00:00
TOKEN_CLEAR (lsp);
for (;;) {
// skip white spaces
while (IS_SPACE(lsp->curc)) NEXT_CHAR (lsp);
// skip the comments here
2006-10-23 14:57:44 +00:00
if (lsp->curc == SSE_T(';')) {
2005-02-04 15:39:11 +00:00
do {
NEXT_CHAR (lsp);
2006-10-23 14:57:44 +00:00
} while (lsp->curc != SSE_T('\n') && lsp->curc != SSE_T_EOF);
2005-02-04 15:39:11 +00:00
}
else break;
}
2006-10-23 14:57:44 +00:00
if (lsp->curc == SSE_T_EOF) {
2005-02-04 15:39:11 +00:00
TOKEN_TYPE(lsp) = TOKEN_END;
return 0;
}
2006-10-23 14:57:44 +00:00
else if (lsp->curc == SSE_T('(')) {
2005-02-04 15:39:11 +00:00
TOKEN_ADD_CHAR (lsp, lsp->curc);
TOKEN_TYPE(lsp) = TOKEN_LPAREN;
NEXT_CHAR (lsp);
return 0;
}
2006-10-23 14:57:44 +00:00
else if (lsp->curc == SSE_T(')')) {
2005-02-04 15:39:11 +00:00
TOKEN_ADD_CHAR (lsp, lsp->curc);
TOKEN_TYPE(lsp) = TOKEN_RPAREN;
NEXT_CHAR (lsp);
return 0;
}
2006-10-23 14:57:44 +00:00
else if (lsp->curc == SSE_T('\'')) {
2005-02-04 15:39:11 +00:00
TOKEN_ADD_CHAR (lsp, lsp->curc);
TOKEN_TYPE(lsp) = TOKEN_QUOTE;
NEXT_CHAR (lsp);
return 0;
}
2006-10-23 14:57:44 +00:00
else if (lsp->curc == SSE_T('.')) {
2005-02-04 15:39:11 +00:00
TOKEN_ADD_CHAR (lsp, lsp->curc);
TOKEN_TYPE(lsp) = TOKEN_DOT;
NEXT_CHAR (lsp);
return 0;
}
2006-10-23 14:57:44 +00:00
else if (lsp->curc == SSE_T('-')) {
2005-02-04 15:39:11 +00:00
TOKEN_ADD_CHAR (lsp, lsp->curc);
NEXT_CHAR (lsp);
2005-09-20 08:05:32 +00:00
if (IS_DIGIT(lsp->curc)) {
return read_number (lsp, 1);
}
else if (IS_IDENT(lsp->curc)) {
return read_ident (lsp);
}
else {
TOKEN_TYPE(lsp) = TOKEN_IDENT;
return 0;
}
2005-02-04 15:39:11 +00:00
}
else if (IS_DIGIT(lsp->curc)) {
return read_number (lsp, 0);
}
else if (IS_ALPHA(lsp->curc) || IS_IDENT(lsp->curc)) {
return read_ident (lsp);
}
2006-10-23 14:57:44 +00:00
else if (lsp->curc == SSE_T('\"')) {
2005-02-04 15:39:11 +00:00
NEXT_CHAR (lsp);
return read_string (lsp);
}
TOKEN_TYPE(lsp) = TOKEN_INVALID;
NEXT_CHAR (lsp); // consume
return 0;
}
2006-10-22 13:10:46 +00:00
static int read_number (sse_lsp_t* lsp, int negative)
2005-02-04 15:39:11 +00:00
{
2006-10-22 13:10:46 +00:00
sse_lsp_int_t ivalue = 0;
sse_lsp_real_t rvalue = 0.;
2005-02-14 14:37:50 +00:00
2005-02-04 15:39:11 +00:00
do {
2006-10-23 14:57:44 +00:00
ivalue = ivalue * 10 + (lsp->curc - SSE_T('0'));
2005-02-04 15:39:11 +00:00
TOKEN_ADD_CHAR (lsp, lsp->curc);
NEXT_CHAR (lsp);
} while (IS_DIGIT(lsp->curc));
2005-09-20 11:19:15 +00:00
/* TODO: extend parsing floating point number */
2006-10-23 14:57:44 +00:00
if (lsp->curc == SSE_T('.')) {
2006-10-22 13:10:46 +00:00
sse_lsp_real_t fraction = 0.1;
2005-02-14 14:37:50 +00:00
2005-09-20 11:19:15 +00:00
NEXT_CHAR (lsp);
2006-10-22 13:10:46 +00:00
rvalue = (sse_lsp_real_t)ivalue;
2005-09-20 11:19:15 +00:00
while (IS_DIGIT(lsp->curc)) {
2006-10-23 14:57:44 +00:00
rvalue += (sse_lsp_real_t)(lsp->curc - SSE_T('0')) * fraction;
2005-09-20 11:19:15 +00:00
fraction *= 0.1;
NEXT_CHAR (lsp);
}
2005-02-04 15:39:11 +00:00
2005-09-20 11:19:15 +00:00
TOKEN_RVALUE(lsp) = rvalue;
TOKEN_TYPE(lsp) = TOKEN_REAL;
if (negative) rvalue *= -1;
}
else {
TOKEN_IVALUE(lsp) = ivalue;
TOKEN_TYPE(lsp) = TOKEN_INT;
if (negative) ivalue *= -1;
}
2005-02-04 15:39:11 +00:00
return 0;
}
2006-10-22 13:10:46 +00:00
static int read_ident (sse_lsp_t* lsp)
2005-02-04 15:39:11 +00:00
{
do {
TOKEN_ADD_CHAR (lsp, lsp->curc);
NEXT_CHAR (lsp);
} while (IS_ALNUM(lsp->curc) || IS_IDENT(lsp->curc));
TOKEN_TYPE(lsp) = TOKEN_IDENT;
return 0;
}
2006-10-22 13:10:46 +00:00
static int read_string (sse_lsp_t* lsp)
2005-02-04 15:39:11 +00:00
{
int escaped = 0;
2006-10-22 13:10:46 +00:00
sse_cint_t code = 0;
2005-02-04 15:39:11 +00:00
do {
2006-10-23 14:57:44 +00:00
if (lsp->curc == SSE_T_EOF) {
2005-02-04 15:39:11 +00:00
TOKEN_TYPE(lsp) = TOKEN_UNTERM_STRING;
return 0;
}
// TODO:
if (escaped == 3) {
/* \xNN */
}
else if (escaped == 2) {
/* \000 */
}
else if (escaped == 1) {
/* backslash + character */
2006-10-23 14:57:44 +00:00
if (lsp->curc == SSE_T('a'))
lsp->curc = SSE_T('\a');
else if (lsp->curc == SSE_T('b'))
lsp->curc = SSE_T('\b');
else if (lsp->curc == SSE_T('f'))
lsp->curc = SSE_T('\f');
else if (lsp->curc == SSE_T('n'))
lsp->curc = SSE_T('\n');
else if (lsp->curc == SSE_T('r'))
lsp->curc = SSE_T('\r');
else if (lsp->curc == SSE_T('t'))
lsp->curc = SSE_T('\t');
else if (lsp->curc == SSE_T('v'))
lsp->curc = SSE_T('\v');
else if (lsp->curc == SSE_T('0')) {
2005-02-04 15:39:11 +00:00
escaped = 2;
code = 0;
NEXT_CHAR (lsp);
continue;
}
2006-10-23 14:57:44 +00:00
else if (lsp->curc == SSE_T('x')) {
2005-02-04 15:39:11 +00:00
escaped = 3;
code = 0;
NEXT_CHAR (lsp);
continue;
}
}
2006-10-23 14:57:44 +00:00
else if (lsp->curc == SSE_T('\\')) {
2005-02-04 15:39:11 +00:00
escaped = 1;
NEXT_CHAR (lsp);
continue;
}
TOKEN_ADD_CHAR (lsp, lsp->curc);
NEXT_CHAR (lsp);
2006-10-23 14:57:44 +00:00
} while (lsp->curc != SSE_T('\"'));
2005-02-04 15:39:11 +00:00
TOKEN_TYPE(lsp) = TOKEN_STRING;
NEXT_CHAR (lsp);
return 0;
}