5

次の入力を消費できる文法を書こうとしています:

begin #this is a example
    x = 56;

    while x > 0 do
    begin
    point 15.6 78.96;
    end;
end;

lexer.l ファイルは次のとおりです。

%option noyywrap

%{
#include "parser.h"
#include <stdlib.h>
#include <stdio.h>
const char * const unrecognizedToken = "Unrecognized token";

%}


NewLine                 \n
WhiteSpaces             [\r\t\f\v ]+
Semicolon                    ;

digit       [0-9]
number1     {digit}+\.?([eE][-+]?{digit}+)?
number2     {digit}*\.{digit}+([eE][-+]?{digit}+)?
double_number      {number1}|{number2}

BEGIN                   "begin"
END                     "end"
WHILE                   "while"
DO                      "do"
POINT                   "point"

%x POINT_DEFINITIONS

%%

{WhiteSpaces} {
    printf("WhiteSpaces");
    printf("\n");
} 

{NewLine}     {
    printf("NewLine");
    printf("\n");
} 


{WHILE} {
    printf("While");
    printf("\n");
    return TOKEN_WHILE;
}

{BEGIN} {
    printf("TOKEN_BEGIN");
    printf("\n");
    return TOKEN_BEGIN;
}

{END}   {
    printf("TOKEN_END");
    printf("\n");
    return TOKEN_END;
}

{DO}    { 
    printf("DO");
    printf("\n");
    return TOKEN_DO;
}

{POINT}                                   { 
    printf("POINT_START");
    printf("\n");
    BEGIN POINT_DEFINITIONS; 
    return TOKEN_POINT; 
}

<POINT_DEFINITIONS>{double_number}             {
    printf("POINT_DEFINITIONS %s", yytext);
    printf("\n");
    yylval.dval = atof(yytext);
    return TOKEN_DOUBLE;
}  

<POINT_DEFINITIONS>{WhiteSpaces}             {
    printf("WhiteSpaces");
    printf("\n");
}  

[a-zA-Z_][a-zA-Z0-9_]* { 
    printf("TOKEN_IDENTIFIER");
    printf("\n");
    yylval.name = strdup(yytext);
    return TOKEN_IDENTIFIER;
}

[()=;]  { 
    printf("yytext = %s", yytext);
    printf("\n");
    return *yytext;
}

[*/+\-<>] { 
    printf("TOKEN_OPERATOR");
    printf("\n");
    yylval.op = *yytext; 
    return TOKEN_OPERATOR;
}

[-]?[0-9]+    {
    printf("TOKEN_VALUE");
    printf("\n");
    yylval.val = atoi(yytext); 
    return TOKEN_VALUE;
 }

#.*         {
    printf("COMMENT");
    printf("\n");
    /*comment*/
}

.           { printf("%s", unrecognizedToken); }

これが parser.y ファイルです。

%error-verbose
%{
#define YYDEBUG 1
%}

%union {
    int val;
    double dval;
    char op;
    char* name;
}

%token TOKEN_BEGIN TOKEN_END TOKEN_WHILE TOKEN_DO TOKEN_POINT TOKEN_OPERATOR TOKEN_VALUE TOKEN_IDENTIFIER TOKEN_DOUBLE 
%start program

%{
void yyerror(const char* const message);

%}

%%

program: statement';';

block: TOKEN_BEGIN statements TOKEN_END { printf("rule block\n"); };

statements:
      statement';' statements { printf("rule statements\n"); }
    |;

statement: 
    | assignment
    | command
    | whileStmt
    | block;

assignment: TOKEN_IDENTIFIER '=' TOKEN_VALUE {
    printf("rule Assignment\n"); 
} ;

whileStmt: TOKEN_WHILE condition TOKEN_DO block {printf("rule While\n");};

condition: TOKEN_IDENTIFIER { printf("rule token_identifier\n"); }
    | TOKEN_VALUE { printf("rule token_value\n"); }
    | condition TOKEN_OPERATOR condition { printf("rule condition TOKEN_OPERATOR condition\n"); };

command: TOKEN_POINT TOKEN_DOUBLE TOKEN_DOUBLE { printf("rule Command\n"); };

%%

#include <stdlib.h>

void yyerror(const char* const message)
{
    printf("Parse error:%s\n", message);
    exit(1);
}

int main()
{
    yyparse();
}

しかし、次のエラーメッセージが表示されます:

Parse error:syntax error, unexpected $end, expecting ';'

次のようにコンパイルされます。

 flex -o lexer.c lexer.l
 bison -v -d -o parser.c parser.y
 gcc parser.c lexer.c -o parser -g -DYYDEBUG=1

パーサーを実行するには:

./parser < example

何が問題なのかを調べるのを手伝ってもらえますか? 文法が上記の例を入力として受け入れられないのはなぜですか?

4

1 に答える 1

3

問題は語彙アナライザーにあります (文法に問題があるかどうかとは関係ありません — 文法を分析していません。なぜなら、最初に語彙アナライザーの問題に気づき、文法が機能しないのに十分だったからです)。

にテストを追加しましmain()lexer.l

%%

YYSTYPE yylval;

int main(void)
{
    int token;
    while ((token = yylex()) != 0)
        printf("Token: %d (%s)\n", token, yytext);
    return 0;
}

次に、サンプル コードで実行して、トークン ストリームが正しく生成されているかどうかを確認しました。私が得た出力は次のとおりです。

TOKEN_BEGIN
Token: 258 (begin)
WhiteSpaces
COMMENT
NewLine
WhiteSpaces
TOKEN_IDENTIFIER
Token: 265 (x)
WhiteSpaces
yytext = =
Token: 61 (=)
WhiteSpaces
TOKEN_VALUE
Token: 264 (56)
yytext = ;
Token: 59 (;)
NewLine
NewLine
WhiteSpaces
While
Token: 260 (while)
WhiteSpaces
TOKEN_IDENTIFIER
Token: 265 (x)
WhiteSpaces
TOKEN_OPERATOR
Token: 263 (>)
WhiteSpaces
TOKEN_VALUE
Token: 264 (0)
WhiteSpaces
DO
Token: 261 (do)
NewLine
WhiteSpaces
TOKEN_BEGIN
Token: 258 (begin)
NewLine
WhiteSpaces
POINT_START
Token: 262 (point)
WhiteSpaces
POINT_DEFINITIONS 15.6
Token: 266 (15.6)
WhiteSpaces
POINT_DEFINITIONS 78.96
Token: 266 (78.96)
;
WhiteSpaces
end;
end;

ご覧のとおり、メイン プログラムに返された最後のトークンは 78.96.

POINT を認識したら、状態 POINT_DEFINITIONS を開始します。ただし、一度その状態になると、永遠にその状態になります。INITIAL 状態に戻ることはありません。おそらく、セミコロンを認識して実行するルールを POINT_DEFINITIONS 開始状態に追加する必要がありますBEGIN INITIAL;

<POINT_DEFINITIONS>{Semicolon} {
    printf("Semicolon in POINT_DEFINITION state\n");
    BEGIN INITIAL;
    return *yytext;
}

これを配置すると、出力の末尾は次のようになります。

...
TOKEN_BEGIN
Token: 258 (begin)
NewLine
WhiteSpaces
POINT_START
Token: 262 (point)
WhiteSpaces
POINT_DEFINITIONS 15.6
Token: 266 (15.6)
WhiteSpaces
POINT_DEFINITIONS 78.96
Token: 266 (78.96)
Semicolon in POINT_DEFINITION state
Token: 59 (;)
NewLine
WhiteSpaces
TOKEN_END
Token: 259 (end)
punctuation: yytext = ;
Token: 59 (;)
NewLine
TOKEN_END
Token: 259 (end)
punctuation: yytext = ;
Token: 59 (;)
NewLine
于 2013-11-02T16:35:41.667 に答える