Wattz
Wattz

Reputation: 21

Space issue with Flex/Bison

Im currently working on an HTML parser/template library using Flex/Bison. I am having some issues with my if statement. The expression parses fine ( if you > me ) but when it comes to the statement between the beginning and ending if tags, it is only getting the first word and dying on the space between them. Just wondering how I can ensure that I get all the content between the tags and not have it die on the first space it encounters.

What Im basically doing is rebuilding the file with the new values from variables ({{var}}) and results from statements (like {% if expression %} blah {% endif %}) (ie. djangoish)

Output


you > me

If Statement: 
if(you) {
    Do
}

Example Template


%{
#include <stdio.h>
#include "ink.tab.h"

using namespace std;

extern "C" {
   int yyparse(void);
   int yylex(void);
   int yywrap();
}

extern void yyerror(char *err);
extern int LINENO;

const char *context;
%}

%%

   /* Open/Close template tags */
"{{"     { return OPENPRINT;   }
"}}"     { return CLOSEPRINT;  }
"{%"     { return OPENACTION;  }
"%}"     { return CLOSEACTION; }


   /* Conditionals */
"!"   { return BANG;  }
"<"   { return LT;    }
">"   { return GT;    }
"=="  { return EQ;    }
"!="  { return NEQ;   }
"<="  { return LTEQ;  }
">="  { return GTEQ;  }
"&&"  { return ANDOP; }
"||"  { return OROP;  }

   /* IF/ELSE handler */
"if"     { return IF_TOKEN;    }
"else"   { return ELSE_TOKEN;  }
"endif"  { return ENDIF_TOKEN; }

   /* FOR handler */
"for"    { return FOR_TOKEN;    }
"in"     { return IN_TOKEN;     }
"endfor" { return ENDFOR_TOKEN; }

   /* Context grab */
[a-zA-Z0-9_]*   { yylval.strval = strdup(yytext); return CONTEXT; }

   /* Excuse the HTML tags */
\&lt;[^>]*\>    { context = strdup(yytext); fwrite(context, sizeof(char), strlen(context), yyout); }

   /* Some catch alls */
[ \t]+     { context = strdup(yytext); fwrite(context, sizeof(char), strlen(context), yyout); }

\n           { LINENO++; context = "\n"; fwrite(context, sizeof(char), strlen(context), yyout); }
.            ;

%%

void yyerror(char *err)
{
   printf("\nLine:\t%d\nError:\t%s\nText:\t%s\n", LINENO, err, yytext);
}

int yywrap()
{
   return 1;
}

int main()
{
   yyout = fopen("test.out", "w");
   yyin = fopen("test.jhtml", "r");
   yyparse();
}

Bison

%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <v8.h>

using namespace std;
using namespace v8;

extern "C" {
   int yyparse(void);
   int yylex(void);
   int yywrap();
}

int LINENO = 1;
void yyerror(char *err);

extern FILE *yyout;
%}


%union {
   int inval;
   char *strval;
}

%token OPENPRINT
%token CLOSEPRINT
%token OPENACTION
%token CLOSEACTION
%token <strval> CONTEXT
%token IF_TOKEN
%token ELSE_TOKEN
%token ENDIF_TOKEN
%token FOR_TOKEN
%token IN_TOKEN
%token ENDFOR_TOKEN
%token TAGS

%token BANG
%token LT
%token GT
%token EQ
%token NEQ
%token LTEQ
%token GTEQ
%token ANDOP
%token OROP

%type <strval> context
%type <strval> expression
%type <strval> contexts

%%

commands:
         command
         |
         commands command
         ;

command:
         OPENPRINT echo CLOSEPRINT
         |
         expression
         |
         stmt
         ;

echo:
         context { 
            char *context = $1;
            fwrite(context, sizeof(char), strlen(context), yyout); 
         }
         ;

stmt:
         OPENACTION IF_TOKEN expression CLOSEACTION contexts OPENACTION ENDIF_TOKEN CLOSEACTION { 
            printf("\nIf Statement: \n");
            printf("if(%s) {\n\t%s\n}\n", $3, $5);
         }
         ;

contexts:
         context
         |
         contexts context
         ;

context:
         CONTEXT { $$ = $1; }
         ;

expression:
         context
         |
         context GT context   { printf("\n%s > %s\n", $1, $3); }
         |
         context LT context      {}
         |
         context EQ context      {}
         |
         context NEQ context     {}
         |
         context LTEQ context    {}
         |
         context GTEQ context    {}
         |
         context ANDOP context   {}
         |
         context OROP context    {}
         |
         BANG context            {}
         ;
%%

Example HTML Template

{% if you > me %}
     Do something here
{% endif %}

Upvotes: 1

Views: 3607

Answers (2)

Polla Toube
Polla Toube

Reputation: 178

Maybe you should add a whitespace token within your command rule.

bison file:

command:
    WHITESPACE {/*do nothing to skip whitespace */}
    | 
    OPENPRINT echo CLOSEPRINT
    |
    expression
    |
    stmt
    ;

flex file:

[ \t\v\n\f]     { count(); return(WHITESPACE); }

Upvotes: 0

riwalk
riwalk

Reputation: 14243

It appears as though you are not returning anything on this line:

[ \t]+     { context = strdup(yytext); fwrite(context, sizeof(char), strlen(context), yyout); }

Without returning anything, it doesn't seem as though it would be recognized as a token, and thus would be ignored.

I'm not 100% sure however. I'm a little confused by your use of the variable "context" (which also seems to be a valid token?), but at any rate that may be your problem.

Upvotes: 1

Related Questions