Проблема с пространством для Flex/Bison

В настоящее время я работаю над библиотекой парсера/шаблона HTML, используя Flex/Bison. У меня есть некоторые проблемы с моим оператором if. Выражение анализируется нормально (если вы > я), но когда дело доходит до утверждения между начальным и конечным тегами if, оно получает только первое слово и умирает на пробеле между ними. Просто интересно, как я могу гарантировать, что я получу весь контент между тегами и не заставлю его умереть в первом месте, которое он встретит.

Что я в основном делаю, так это перестраиваю файл с новыми значениями из переменных ({{var}}) и результатов операторов (например, {% if expression %} blah {% endif %}) (т.е. djangoish)

Вывод


you > me

If Statement: 
if(you) {
    Do
}

Пример шаблона


%{
#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();
}

Бизон

%{
#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            {}
         ;
%%

Пример HTML-шаблона

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

person Wattz    schedule 26.08.2010    source источник
comment
Здесь есть вопрос? Грамматика и лексер отлично компилируются и прекрасно принимают входной пример, производя результат, описанный как ожидалось...   -  person Chris Dodd    schedule 07.05.2013


Ответы (2)


Похоже, вы ничего не возвращаете в этой строке:

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

Ничего не возвращая, не похоже, что он будет распознан как токен и, следовательно, будет проигнорирован.

Однако я не уверен на 100%. Меня немного смущает ваше использование переменной «контекст» (которая также кажется допустимым токеном?), но, во всяком случае, это может быть вашей проблемой.

person riwalk    schedule 26.08.2010
comment
контекст - это просто локальный константный символ, который я использую для временного хранения значения, поэтому я могу записать его обратно в файл, чтобы сохранить файловую структуру для пространства, вкладок и html. Также спасибо за ответ, причина, по которой я ничего не вернул, заключается в том, что я все еще хочу игнорировать пробелы, но должен ли я возвращать что-то вроде * yytext? - person Wattz; 26.08.2010

Возможно, вам следует добавить токен пробела в ваше командное правило.

файл бизона:

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

гибкий файл:

[ \t\v\n\f]     { count(); return(WHITESPACE); }
person Cedric    schedule 06.07.2018