aandis
aandis

Reputation: 4222

passing a substring to a function

I am working on building the LISP interpreter. The problem I am stuck at is where I need to send the entire substring to a function as soon as I encounter a "(". For example, if I have,

( begin  ( set x  2 ) (set y 3 ) )

then I need to pass

begin  ( set x  2 ) (set y 3 ) )

and when I encounter "(" again I need to pass

set x  2 ) (set y 3 ) )

then

set y 3 ) )

I tried doing so with substr by calculating length, but that didn't quite work. If anyone could help, that'd be great.

Requested code

int a=0;
listnode *makelist(string t) //t is the substring 
{
     //some code
     istringstream iss(t); 
     string word;
     while(iss>>word){
         if(word=="(")//I used strcmp here. Just for the sake for time saving I wrote this
         //some operations
             int x=word.size();
     a=a+x;
     word=word.substr(a);
     p->down=makelist(word);//function called again and word here should be the substring
}}

Upvotes: 0

Views: 493

Answers (3)

Vatine
Vatine

Reputation: 21288

Normally, lisp parsing is done by recursively calling a reader and let the reader "consume" as much data as is necessary. If you're doing this on strings, it may be handy to pass the same string around, by reference, and return a tuple of "this is what I read" and "this is where I finished reading".

So something like this (obviously, in actual code, you may want to pass pointers to offset rather than have a pair-structure and needing to deal with memory-management of that, I elided that to make the code more readable):

struct readthing {
  Node *data;
  int offset
}

struct readthing *read (char *str, int offset) {
  if (str[offset] == '(')
    return read_delimited(str, offset+1, ')'); /* Read a list, consumer the start */
  ...
}

struct readthing *read_delimited (char *str, int offset, char terminator) {
  Node *list  = NULL;
  offset = skip_to_next_token(str, offset);
  while (str[offset] != terminator) {
    struct readthing *foo = read(str, offset);
    offset = foo->offset;
    list = do_cons(foo->data, list);
  }
  return make_readthing(do_reverse(list), offset+1);
}

Upvotes: 0

PuercoPop
PuercoPop

Reputation: 6807

Have you thought of using an intermediate representation? So first parse all whole string to a data structure and then execute it? After all Lisps have had traditionally applicative order which means they evaluate the arguments first before calling the function. The data structure could look something along the lines of a struct which has the first part of the string (ie begin or set in your example) and the rest of the string to process in as a second property (head and rest if you want). Also consider that Trees are more easily constructed through recursion than through iteration, the base case here being reaching the ')' character.

If you are interested in Lisp interpreters and compilers you should checkout Lisp in Small Pieces, well worth the price.

Upvotes: 1

Mats Petersson
Mats Petersson

Reputation: 129494

I would have thought soemthing like this:

string str = "( begin  ( set x  2 ) (set y 3 ) )";

func(str);

...

void func(string s)
{
    int i = 0;
    while(s.size() > i)
    {
        if (s[i] == '(')
        {
           func(s.substr(i)); 
        }

        i++;
    }
}

would do the job. [Obviously, you'll perhaps want to do something else in there too!]

Upvotes: 0

Related Questions