1
votes

I want to sum the numbers on a single line.

e.g.

1 2 3 '\n'   =>  prints 6
1 '\n'       =>  prints 1
0 '\n'       =>  prints 0
'\n'         =>  prints 0

For this purpose, I have figured that following regular expression would suffice :

 ((NUMBER)* "\n")+

I make use of lex/yacc combo for it. I understand that lex would suffice but this is just a small throwaway program specifically to know how yacc works.

I made the following grammar for the above regular expression :

lines -> lines line
lines -> line

line -> numbers '\n'

numbers -> numbers NUMBER
numbers -> (empty)

But putting the input as 1 (enter) generates segmentation fault. I cannot understand why it is happening.


The yacc program (in.y) is:

%{
#include <stdio.h>

extern int yylex();
int yyerror(const char *s);

%}

%union
{
    int num;
    char ch;
}

%token <num> NUMBER
%type  <num> numbers


%start lines

%%

lines   :   line lines      ;
        |   line            ;
        ;

line    :   numbers '\n'    { printf("%s\n", $1); }

numbers :   NUMBER numbers  { $$ = $1 + $2; }
        |   NUMBER          { $$ = $1; }
        ;

%%

int main()
{
    return( yyparse() );
}

int yyerror(const char * s)
{
    fprintf( stderr, "%s\n", s );
}

And the lex program is (in.l):

%{
#include "y.tab.h"

//extern YYSTYPE yylval;
%}

%%

[0-9]+      { yylval.num = atoi(yytext); return NUMBER; }
\n          { return yylval.ch = yytext[0]; }
.           { ; }

%%

int yywrap()
{
        return 1;
}

To be exhaustive, I am running it under Cygwin emulating using flex/bison as:

yacc -d in.y; flex in.l; gcc y.tab.c lex.yy.c

1

1 Answers

3
votes

If you compile your code with gcc flag -s and then run your program (a.out) using valgrind (a memory error detector), you would discover that the problem is on the printf.

So when you have a %s argument on the printf, it will be waiting for a pointer to a null-terminated string. However, you are passing an integer. When printf is accessing it will start at the address on $1 and the continue till a \0 (null char) appear in the memory.

You just want to print a simple integer. Replace the %s with %d and it will work.

The entire rule looks like that:

line    :   numbers '\n'    { printf("%d\n", $1); }