416 lines
8.5 KiB
C
416 lines
8.5 KiB
C
/*************************************************************************
|
|
*
|
|
* lispParse.c --
|
|
*
|
|
* This module contains the mini-scheme command-line parser (ugh).
|
|
*
|
|
* (c) 1996 California Institute of Technology
|
|
* Department of Computer Science
|
|
* Pasadena, CA 91125.
|
|
*
|
|
* Permission to use, copy, modify, and distribute this software
|
|
* and its documentation for any purpose and without fee is hereby
|
|
* granted, provided that the above copyright notice appear in all
|
|
* copies. The California Institute of Technology makes no representations
|
|
* about the suitability of this software for any purpose. It is
|
|
* provided "as is" without express or implied warranty. Export of this
|
|
* software outside of the United States of America may require an
|
|
* export license.
|
|
*
|
|
* $Header$
|
|
*
|
|
*************************************************************************/
|
|
|
|
#include <stdio.h>
|
|
#include <ctype.h>
|
|
|
|
#include "lisp/lisp.h"
|
|
#include "lispInt.h"
|
|
#include "textio/textio.h"
|
|
#include "utils/hash.h"
|
|
#include "utils/malloc.h"
|
|
|
|
#define IsSpace(c) ((c) == ' ')
|
|
|
|
#define BeginIdChar(c) (isalpha(c) || (c) == '+' || (c) == '-' || \
|
|
(c) == '.' || (c) == '*' || (c) == '/' || \
|
|
(c) == '<' || (c) == '=' || (c) == '>' || \
|
|
(c) == '!' || (c) == '?' || (c) == ':' || \
|
|
(c) == '$' || (c) == '%' || (c) == '_' || \
|
|
(c) == '&' || (c) == '~' || (c) == '^' || \
|
|
(c) == '#' || (c) == '@' || (c) == ',')
|
|
|
|
#define IsIdChar(c) (BeginIdChar(c) || isdigit(c) || ((c) == '[') || \
|
|
((c) == ']'))
|
|
|
|
#define ISEND(c) ((c) == '\0' || isspace(c) || (c) == ')' || (c) == '(')
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
*
|
|
* Various string munging functions
|
|
*
|
|
*-----------------------------------------------------------------------------
|
|
*/
|
|
|
|
/*
|
|
strip whitespace from left: returns new string pointer
|
|
*/
|
|
static char *
|
|
stripleft (s)
|
|
char *s;
|
|
{
|
|
while (*s && IsSpace (*s))
|
|
s++;
|
|
return s;
|
|
}
|
|
|
|
#define STRINGTAB 1000
|
|
|
|
static int nstrings = 0;
|
|
HashTable Strings;
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
*
|
|
* LispNewString --
|
|
*
|
|
* Returns a unique string pointer corresponding to string "s"
|
|
*
|
|
*-----------------------------------------------------------------------------
|
|
*/
|
|
char *LispNewString (s)
|
|
char *s;
|
|
{
|
|
int i;
|
|
HashEntry *h;
|
|
|
|
if (nstrings == 0)
|
|
HashInit (&Strings, STRINGTAB, HT_STRINGKEYS);
|
|
|
|
h = HashLookOnly (&Strings, s);
|
|
if (h)
|
|
i = (int) HashGetValue(h);
|
|
else {
|
|
i = nstrings++;
|
|
h = HashFind (&Strings, s);
|
|
HashSetValue (h, i);
|
|
}
|
|
return h->h_key.h_name;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
*
|
|
* LispStringId --
|
|
*
|
|
* Returns an integer identifier associated with string, used for
|
|
* faster function table lookup.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* None.
|
|
*
|
|
*-----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
LispStringId (s)
|
|
char *s;
|
|
{
|
|
int i;
|
|
HashEntry *h;
|
|
|
|
h = HashLookOnly (&Strings, s);
|
|
if (!h)
|
|
i = -1;
|
|
else
|
|
i = (int)HashGetValue (h);
|
|
return i;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
*
|
|
* LispAtomParse --
|
|
*
|
|
* Parse an atom.
|
|
* If within a quote, 'quoted' is 1.
|
|
*
|
|
* Results:
|
|
* Returns pointer to an object.
|
|
*
|
|
* Side effects:
|
|
* None.
|
|
*
|
|
*-----------------------------------------------------------------------------
|
|
*/
|
|
|
|
LispObj *
|
|
LispAtomParse (pstr,quoted)
|
|
int quoted;
|
|
char **pstr;
|
|
{
|
|
char *str = *pstr;
|
|
char *q, c;
|
|
LispObj *l;
|
|
int r;
|
|
char *t;
|
|
|
|
l = LispNewObj ();
|
|
|
|
if ((*str == '+' || *str == '-' || *str == '.') && ISEND(*(str+1))) {
|
|
str++;
|
|
*str = '\0';
|
|
LTYPE(l) = S_SYM;
|
|
LSYM(l) = LispNewString (str-1);
|
|
*pstr = str+1;
|
|
return l;
|
|
}
|
|
if ((isdigit(*str) || *str == '.' || *str == '-' || *str == '+') &&
|
|
(isdigit(str[1]) || str[1] == '.' || str[1] == '-' || str[1] == '+'
|
|
|| ISEND(str[1]))) {
|
|
/* eat leading sign */
|
|
q = str;
|
|
r = 0;
|
|
if (*str == '-' || *str == '+')
|
|
str++;
|
|
if (!*str) {
|
|
TxPrintf ("Invalid number\n");
|
|
*pstr = str;
|
|
return NULL;
|
|
}
|
|
while (*str && isdigit (*str))
|
|
str++;
|
|
if (*str && *str == '.') {
|
|
r = 1;
|
|
str++;
|
|
}
|
|
while (*str && isdigit(*str))
|
|
str++;
|
|
c = *str;
|
|
*str = '\0';
|
|
if (r) {
|
|
LTYPE(l) = S_FLOAT;
|
|
sscanf (q, "%lf", &LFLOAT(l));
|
|
}
|
|
else {
|
|
LTYPE(l) = S_INT;
|
|
sscanf (q, "%d", &LINTEGER(l));
|
|
}
|
|
*str = c;
|
|
}
|
|
else if (*str == '\"') {
|
|
str++;
|
|
q = str;
|
|
while (*str != '\"') {
|
|
if (!*str) {
|
|
TxPrintf ("Unterminated string\n");
|
|
*pstr = str;
|
|
return NULL;
|
|
}
|
|
if (*str == '\\') {
|
|
if (*(str+1))
|
|
str++;
|
|
else {
|
|
TxPrintf ("Trailing character constant\n");
|
|
*pstr = str;
|
|
return NULL;
|
|
}
|
|
}
|
|
str++;
|
|
}
|
|
*str = '\0';
|
|
LTYPE(l) = S_STRING;
|
|
LSTR(l) = (char *) mallocMagic((unsigned) (strlen (q)+1));
|
|
strcpy (LSTR(l), q);
|
|
*str = '\"';
|
|
str++;
|
|
}
|
|
else if (!quoted && str[0] == '#' && (str[1] == 't'|| str[1] == 'f') &&
|
|
ISEND(str[2])) {
|
|
LTYPE(l) = S_BOOL;
|
|
LBOOL(l) = (str[1] == 't') ? 1 : 0;
|
|
str+=2;
|
|
}
|
|
else if (BeginIdChar(*str) || (*str == '\\')) {
|
|
int nest;
|
|
|
|
LTYPE(l) = S_SYM;
|
|
t = q = str;
|
|
if (*str == '\\') {
|
|
*t = *++str;
|
|
t++;
|
|
str++;
|
|
}
|
|
nest = 0;
|
|
while (*str && IsIdChar (*str) || *str == '(' || (*str == ')' && nest>0)) {
|
|
*t = *str;
|
|
if (*str == '(') nest++;
|
|
if (*str == ')') nest--;
|
|
str++;
|
|
if (*str == '\\') {
|
|
*t = *++str;
|
|
str++;
|
|
}
|
|
t++;
|
|
}
|
|
c = *t;
|
|
*t = '\0';
|
|
LSYM(l) = LispNewString (q);
|
|
*t = c;
|
|
}
|
|
else {
|
|
TxPrintf ("Unparsable input character: %c\n", *str);
|
|
*pstr = str;
|
|
return NULL;
|
|
}
|
|
*pstr = str;
|
|
return l;
|
|
}
|
|
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
*
|
|
* LispIParse --
|
|
*
|
|
* Parse a string to a Sexp.
|
|
*
|
|
* Results:
|
|
* Returns pointer to a Sexp.
|
|
*
|
|
* Side effects:
|
|
* None.
|
|
*
|
|
*-----------------------------------------------------------------------------
|
|
*/
|
|
|
|
Sexp *
|
|
LispIParse (pstr)
|
|
char **pstr;
|
|
{
|
|
char *str = *pstr;
|
|
Sexp *s;
|
|
Sexp *ret = NULL;
|
|
Sexp **sptr;
|
|
|
|
str = stripleft (str);
|
|
if (!*str) {
|
|
TxPrintf ("Input malformed\n");
|
|
return NULL;
|
|
}
|
|
while (*str != ')') {
|
|
if (!*str) {
|
|
TxPrintf ("Input malformed: missing )\n");
|
|
return NULL;
|
|
}
|
|
s = LispNewSexp ();
|
|
if (*str == '(') {
|
|
CAR(s) = LispNewObj ();
|
|
LTYPE(CAR(s)) = S_LIST;
|
|
str++;
|
|
LLIST(CAR(s)) = LispIParse (&str);
|
|
if (*str != ')') {
|
|
*pstr = str;
|
|
return NULL;
|
|
}
|
|
str++;
|
|
}
|
|
else if (*str == '\'') {
|
|
LispObj *l;
|
|
Sexp *t;
|
|
t = s;
|
|
CAR(s) = LispNewObj ();
|
|
LTYPE(CAR(s)) = S_SYM;
|
|
LSYM(CAR(s)) = LispNewString ("quote");
|
|
CDR(s) = LispNewObj ();
|
|
LTYPE(CDR(s)) = S_LIST;
|
|
LLIST(CDR(s)) = LispNewSexp ();
|
|
s = LLIST(CDR(s));
|
|
CDR(s) = LispNewObj ();
|
|
LTYPE(CDR(s)) = S_LIST;
|
|
LLIST(CDR(s)) = NULL;
|
|
str++;
|
|
str = stripleft (str);
|
|
if (*str == '(') {
|
|
str++;
|
|
CAR(s) = LispNewObj ();
|
|
LTYPE(CAR(s)) = S_LIST;
|
|
LLIST(CAR(s)) = LispIParse (&str);
|
|
if (*str != ')') {
|
|
*pstr = str;
|
|
return NULL;
|
|
}
|
|
str++;
|
|
}
|
|
else {
|
|
if (!(CAR(s) = LispAtomParse (&str,1))) {
|
|
*pstr = str;
|
|
return NULL;
|
|
}
|
|
}
|
|
*pstr = str;
|
|
l = LispNewObj ();
|
|
LTYPE(l) = S_LIST;
|
|
LLIST(l) = t;
|
|
t = LispNewSexp ();
|
|
CAR(t) = l;
|
|
s = t;
|
|
}
|
|
else {
|
|
if (!(CAR(s) = LispAtomParse (&str,0))) {
|
|
*pstr = str;
|
|
return NULL;
|
|
}
|
|
}
|
|
CDR(s) = LispNewObj ();
|
|
LTYPE(CDR(s)) = S_LIST;
|
|
if (ret == NULL)
|
|
ret = s;
|
|
else
|
|
*sptr = s;
|
|
sptr = &LLIST(CDR(s));
|
|
str = stripleft (str);
|
|
}
|
|
if (ret)
|
|
*sptr = NULL;
|
|
*pstr = str;
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
*
|
|
* LispParseString --
|
|
*
|
|
* Parse string to a lisp object.
|
|
*
|
|
* Results:
|
|
* Returns pointer to the object.
|
|
*
|
|
* Side effects:
|
|
* None.
|
|
*
|
|
*-----------------------------------------------------------------------------
|
|
*/
|
|
|
|
LispObj *
|
|
LispParseString (str)
|
|
char *str;
|
|
{
|
|
LispObj *l;
|
|
|
|
str = stripleft (str);
|
|
if (*str != '(')
|
|
l = LispAtomParse (&str,0);
|
|
else {
|
|
str++;
|
|
l = LispNewObj ();
|
|
LTYPE(l) = S_LIST;
|
|
LLIST(l) = LispIParse (&str);
|
|
if (LLIST(l) && *str != ')')
|
|
l = NULL;
|
|
}
|
|
return l;
|
|
}
|