Thread: Simple parser

  1. #1
    Registered User
    Join Date
    Jun 2008
    Posts
    266

    Simple parser

    I made a small Scheme interpreter(without functions and other fancy stuff) a while ago but ran into a few problems. Anyways here's the source:

    Code:
    #include <ctype.h>
    #include <math.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int eval(char *s);
    int isnumber(char *s);
    
    int main(void)
    {
    	char e[201];
    
    	for(;;)
    	{
    		printf("<");
    		fgets(e, 200, stdin);
    		printf(">%d\n", eval(e));
    	}
    
    	return EXIT_SUCCESS;
    }
    
    int eval(char *s)
    {
    	int  ans;
    	int  narg[2];
    	char sarg[2][101];
    	int  i;
    	char op;
    
    	sscanf(s, "(%c %100s %100s)", &op, sarg[0], sarg[1]);
    	narg[0] = isnumber(sarg[0]) ? atoi(sarg[0]) : eval(sarg[0]);
    	narg[1] = isnumber(sarg[1]) ? atoi(sarg[1]) : eval(sarg[1]);
    
    	switch(op)
    	{
    		case '+':
    			ans = narg[0] + narg[1];
    			break;
    		case '-':
    			ans = narg[0] - narg[1];
    			break;
    		case '*':
    			ans = narg[0] * narg[1];
    			break;
    		case '/':
    			ans = narg[0] / narg[1];
    			break;
    	}
    
    	return ans;
    }
    
    int isnumber(char *s)
    {
    	int i;
    
    	for(i = 0; s[i] != '\0'; i++)
    	{
    
    		if(!isdigit(s[i]))
    		{
    			return 0;
    		}
    
    	}
    
    	return 1;
    }
    The biggest problem if the scanf in eval() doesn't quite do what I wanted. Instead of reading the whole (...) expression, only the characters up to the first space are read. Can anyone think of a good solution to this? The other problem is I'm getting a seg fault somewhere but I can't seem to find it.
    Fried chicken for everybody!
    -Kernel Sanders

  2. #2
    Registered User
    Join Date
    Sep 2007
    Posts
    1,012
    Your second %100s in the sscanf() is the likely culprit. If you type in, say, (+ 3 3), sscanf() will read '+', "3", and "3)". That is, it doesn't know that you don't want the ) as part of the string. You can use %100[^)] instead of %s; look up the %[ conversion if you're unfamiliar with it.

    Incidentally, when you're calling fgets(), you needn't subtract one from the size of your buffer. fgets() is smart enough to do what's proper, which is why you'll often see something like:
    Code:
    char buf[50];
    fgets(buf, sizeof buf, stdin);

  3. #3
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    I don't use sscanf much, personally, but it didn't seem to like the parenthesis, when I ran it. What are you trying to do, anyway - some sort of recursive reverse polish notation? I don't know if sscanf can handle something like that. Maybe try parsing it 'manually' (recursive decent, for example).

  4. #4
    Registered User
    Join Date
    Jun 2008
    Posts
    266
    Just a scheme-like interpreter thing ex.(+ (+ 1 1) 2). I'm really new to interpreter design so this is all I could really come up with. Does anyone know a good online tutorial(book possibly) that teaches how to do this more efficiently?
    Fried chicken for everybody!
    -Kernel Sanders

  5. #5
    Registered User
    Join Date
    Jun 2008
    Posts
    266
    Quote Originally Posted by cas View Post
    Your second %100s in the sscanf() is the likely culprit. If you type in, say, (+ 3 3), sscanf() will read '+', "3", and "3)". That is, it doesn't know that you don't want the ) as part of the string. You can use %100[^)] instead of %s; look up the %[ conversion if you're unfamiliar with it.

    Incidentally, when you're calling fgets(), you needn't subtract one from the size of your buffer. fgets() is smart enough to do what's proper, which is why you'll often see something like:
    Code:
    char buf[50];
    fgets(buf, sizeof buf, stdin);
    I don't think thats the problem because I have gotten it to work with just constants eg. (+ 2 2). What I did since then I wish I knew...
    Fried chicken for everybody!
    -Kernel Sanders

  6. #6
    Registered User
    Join Date
    Sep 2007
    Posts
    1,012
    It is a problem, but there are more problems still (related to sscanf() as well) when you're trying something like (+ (+ 1 1) 2).

    Your first go around, with "(%c %100s %100s)", will read this: '+'; "(+"; "1"

    If you don't believe me, try printing them out right after your sscanf(). So sarg[0] is not a number, and thus you call eval("(+"), which is not at all what you want. At the very least you should check the return value of sscanf() to see if it converted what you thought it did. Here you'd see it doesn't.

    Parsing in C is a royal pain. I'm not familiar with scheme, so I don't know how well it lends itself to this, but perhaps you'd be better off with lex and yacc for building a parser for it.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. creating very simple text editor using c
    By if13121 in forum C Programming
    Replies: 9
    Last Post: 10-19-2010, 05:26 PM
  2. Simple message encryption
    By Vicious in forum C++ Programming
    Replies: 10
    Last Post: 11-07-2004, 11:48 PM
  3. Binary Search Trees Part III
    By Prelude in forum A Brief History of Cprogramming.com
    Replies: 16
    Last Post: 10-02-2004, 03:00 PM
  4. Simple simple program
    By Ryback in forum C++ Programming
    Replies: 10
    Last Post: 09-09-2004, 05:48 AM
  5. Need help with simple DAQ program
    By canada-paul in forum C++ Programming
    Replies: 12
    Last Post: 03-15-2002, 08:52 AM