这个Bison语法有什么问题?

雅各布·阿法特尔(Jakob Abfalter)

我试图建立一个Bison语法,似乎缺少了一些东西。我将其保持为非常基本,但仍然遇到语法错误,无法弄清原因:

这是我的野牛密码:

%{

#include <stdlib.h>
#include <stdio.h>

int yylex(void);
int yyerror(char *s);

%}

// Define the types flex could return
%union {
    long lval;
    char *sval;
}

// Define the terminal symbol token types
%token <sval> IDENT;
%token <lval> NUM;

%%

Program: 
    Def ';' 
    ;

Def: 
    IDENT '=' Lambda { printf("Successfully parsed file"); }
    ;

Lambda: 
    "fun" IDENT "->" "end"
    ;

%%

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

int yyerror(char *s)
{
  extern int yylineno;  // defined and maintained in flex.flex
  extern char *yytext;  // defined and maintained in flex.flex

  printf("ERROR: %s at symbol \"%s\" on line %i", s, yytext, yylineno); 
  exit(2);
}

这是我的Flex代码

%{
#include <stdlib.h>
#include "bison.tab.h"
%}

ID [A-Za-z][A-Za-z0-9]*
NUM [0-9][0-9]*
HEX [$][A-Fa-f0-9]+
COMM [/][/].*$

%%

fun|if|then|else|let|in|not|head|tail|and|end|isnum|islist|isfun    {
    printf("Scanning a keyword\n");
}


{ID}    {
    printf("Scanning an IDENT\n");
    yylval.sval =  strdup( yytext );
    return IDENT;
}

{NUM}   {
    printf("Scanning a NUM\n");
    /* Convert into long to loose leading zeros */
    char *ptr = NULL;
    long num = strtol(yytext, &ptr, 10);
    if( errno == ERANGE ) {
            printf("Number was to big");
            exit(1);
    }

    yylval.lval = num;
    return NUM;
}

{HEX}   {
    printf("Scanning a NUM\n");
    char *ptr = NULL;
    /* convert hex into decimal using offset 1 because of the $ */
    long num = strtol(&yytext[1], &ptr, 16);
    if( errno == ERANGE ) {
            printf("Number was to big");
            exit(1);
    }

    yylval.lval = num;
    return NUM;
}


";"|"="|"+"|"-"|"*"|"."|"<"|"="|"("|")"|"->" {
    printf("Scanning an operator\n");
}

[ \t\n]+ /* eat up whitespace */


{COMM}* /* eat up one-line comments */

.   {
    printf("Unrecognized character: %s at linenumber %d\n", yytext, yylineno );
    exit(1);
}

%%

这是我的Makefile

all:    parser

parser: bison flex
    gcc bison.tab.c lex.yy.c -o parser -lfl

bison:  bison.y
    bison -d bison.y

flex:   flex.flex
    flex flex.flex

clean:
    rm bison.tab.h
    rm bison.tab.c
    rm lex.yy.c
    rm parser

一切编译都很好,我没有遇到任何让runnin make all的错误。

这是我的测试文件

f = fun x -> end;

这是输出:

./parser < a0.0
Scanning an IDENT
Scanning an operator
Scanning a keyword
Scanning an IDENT
ERROR: syntax error at symbol "x" on line 1

由于x似乎被识别为IDENT,因此规则应该正确,但我仍然感到语法错误。

我觉得自己错过了一些重要的事情,希望有人可以帮助我。

提前致谢!

编辑:

我试图删除IDENTLambda规则和测试文件中的,现在似乎可以通过该行运行了,但仍会抛出

ERROR: syntax error at symbol "" on line 1

在EOF之后。

您的扫描仪可以识别关键字(并打印出调试行,但请参见下文),但不会麻烦向解析器报告任何内容。因此,它们实际上被忽略了。

在您的野牛定义文件中,您使用(例如)“ fun”作为终端,但没有为终端提供可以在扫描仪中使用的名称。扫描程序需要此名称,因为它必须将令牌ID返回到解析器。

总而言之,您需要的是这样的:

在您的语法中,在之前%%

token T_FUN "fun"
token T_IF "if"
token T_THEN "then"
 /* Etc. */

在您的扫描仪定义中:

fun { return T_FUN; }
if  { return T_IF; }
then { return T_THEN; }
 /* Etc. */

其他一些注意事项:

  1. 您用于识别运算符的扫描仪规则也无法返回任何内容,因此运算符也将被忽略。这显然是不可取的。flex和bison为单字符运算符提供了一种更简单的解决方案,即让字符成为其自己的令牌id。这样避免了创建令牌名称的麻烦。在解析器中,单引号字符表示令牌id,其值是该字符;这与双引号字符串完全不同,双引号字符串是声明的令牌名称的别名。因此,您可以这样做:

    "=" { return '='; }
     /* Etc. */
    

    但是一次完成所有单字符令牌会更容易:

    [;+*.<=()-]  { return yytext[0]; }
    

    甚至更容易在最后使用默认规则:

    . { return yytext[0]; }
    

    通过向解析器返回未知的令牌ID,将具有处理无法识别的字符的效果,这将导致语法错误。

    这不适用于“->”,因为它不是单个字符标记,必须以与关键字相同的方式进行处理。

  2. 如果-d在创建扫描仪时使用该标志,则Flex将自动生成调试输出这比插入您自己的调试打印输出要容易得多,因为您可以通过简单地删除该-d选项将其关闭%option debug如果您不想更改makefile中的flex调用,则可以改用它。)这样做也更好,因为它提供了一致的信息,包括位置信息。

  3. 一些小要点:

    • 该模式[0-9][0-9]*可以更容易地编写[0-9]+
    • 注释模式"//".*不需要$在末尾先行,因为.*它将始终匹配最长的非换行字符序列。因此,第一个不匹配的字符必须是换行符或EOF。$如果模式以EOF终止,则lookahead将不匹配,如果文件以注释结尾且末尾没有换行符,则会导致奇数错误。
    • 没有任何用处,{COMM}*因为注释模式与终止注释的换行符不匹配,因此不可能有两个连续的注释匹配。但是无论如何,在匹配注释和以下换行符之后,flex将继续匹配以下注释,因此{COMM}就足够了。(个人而言,我不会使用该COMM缩写;它确实不会增加可读性,恕我直言。)

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

这个Bison语法有什么问题?

来自分类Dev

这个Gradle语法有什么问题?

来自分类Dev

这个 for Loop 语法有什么问题?

来自分类Dev

这个 ANTLR 语法有什么问题?

来自分类Dev

这个简单的Python列表的语法有什么问题?

来自分类Dev

这个MySQL查询日期的语法有什么问题?

来自分类Dev

这个sqlite代码的语法有什么问题?

来自分类Dev

这个 SQL 命令的语法有什么问题

来自分类Dev

这个GStreamer管道有什么问题?

来自分类Dev

这个xsl:key有什么问题?

来自分类Dev

这个ANDEngine HUD有什么问题?

来自分类Dev

这个lua编码有什么问题?

来自分类Dev

这个dockerfile有什么问题

来自分类Dev

这个grep命令有什么问题?

来自分类Dev

这个续集查询有什么问题

来自分类Dev

这个Unban命令有什么问题

来自分类Dev

这个C代码有什么问题?

来自分类Dev

这个python命令有什么问题?

来自分类Dev

这个脚本有什么问题?

来自分类Dev

这个简单的登录有什么问题

来自分类Dev

这个Java HashMap有什么问题?

来自分类Dev

这个PHP函数有什么问题?

来自分类Dev

这个Linq查询有什么问题

来自分类Dev

这个while循环有什么问题?

来自分类Dev

这个glsl代码有什么问题?

来自分类Dev

这个grep有什么问题?

来自分类Dev

这个Ebean请求有什么问题

来自分类Dev

这个PDO脚本有什么问题

来自分类Dev

这个python代码有什么问题