【问题标题】:How to write a YACC token catchall rule如何编写 YACC 令牌包罗万象的规则
【发布时间】:2013-08-15 18:59:27
【问题描述】:

作为学习曲线练习,我使用 lex 和 yacc 将“C”头文件转换为我的 Prolog 编译器可以用来调用 dll 和从 lib 文件中提取 objs 的东西。编译器需要方法名和参数才能传递。例如

WINGDIAPI void APIENTRY glAccum (GLenum op, GLfloat value);
WINGDIAPI void APIENTRY glAlphaFunc (GLenum func, GLclampf ref);
WINGDIAPI GLboolean APIENTRY glAreTexturesResident (GLsizei n, const GLuint *textures, GLboolean *residences);
WINGDIAPI void APIENTRY glArrayElement (GLint i);

应该转化为

glAccum (unsigned op, core::real32 value);
glAlphaFunc (unsigned func, core::real32 ref);
glAreTexturesResident (integer n, pointer textures, pointer residences) -> core::char8;
glArrayElement (integer i);

在头文件开头使用一些typedef

typedef unsigned int GLenum;
typedef unsigned char GLboolean;
typedef unsigned int GLbitfield;
typedef signed char GLbyte;
typedef short GLshort;
typedef int GLint;
typedef int GLsizei;
typedef unsigned char GLubyte;
typedef unsigned short GLushort;
typedef unsigned int GLuint;
typedef float GLfloat;
typedef float GLclampf;
typedef double GLdouble;
typedef double GLclampd;
typedef void GLvoid;

有一个额外的表可以将“C”内置类型转换为 Prolog 内置类型。

我已经为我当前需要的所有标记准备了一个可以工作的词法分析器。 我的问题是。在我项目的 yacc 部分中编写规则时。如何编写一个全局规则来捕获我尚未编写规则的所有 TOKENS,以便我可以逐步处理我的项目。编写和测试每条规则。我要做的第一件事是捕获 typedef 并将它们的关联写入一个小的查找表,以便稍后在处理函数和参数列表时,我可以插入正确的 PROLOG 原语。请注意。我不是在问如何编写规则来捕获 typedef。这我有一个粗略的想法。我在问如何在我开发我的项目时,对我的“lexer”返回到“yaccer”的所有其他 TOKEN 进行全局捕获。在“词法分析器”中,您通常有一个空函数调用,对正在读取的文本不做任何事情。

“LATER”         |
“JUNK”          |
{WS}+           |
\n              |
.               ;

什么是 YACC 等价物。

【问题讨论】:

  • Yacc 将为您的解析器尚未处理的任何标记序列生成“语法错误”。
  • 正确。请参阅我的 cmets 对 jaeheung 8 月 21 日 5:04 的回答。

标签: token yacc rules


【解决方案1】:

一旦 yyparse() 遇到与任何已知语法不匹配的输入,它就会调用 yyerror() 函数。 参考 Yacc 手册的“错误处理”部分。

【讨论】:

  • 正确。但是如何开发一个'YACCer'。采用中等复杂的语言,例如“C”。很少有人可以坐下来编写所有 YACC 规则来立即解析“C”。我认为必须编写某种类型的全局规则才能捕获所有内容。然后开始一一编写单独的规则,测试和改进。将令牌从全局规则移动到单个规则,直到所有令牌都被正确使用并且您的解析完成。
【解决方案2】:

我猜你想要错误恢复。 这是我的错误恢复实现的一部分:

line:   stmt eol
        { $$ = $1;}
        | T_NEWLINE
        { $$ = NULL;}
        | error T_NEWLINE
        {
                $$ = NULL;
                yyerrok;
        }

当出现语法错误时,第三条规则使解析器跳到下一行输入并继续解析。 yyerror() 仍然被调用。不确定何时调用它,但我的猜测是在调用错误规则之前。 您仍然需要阅读手册的“错误恢复”部分。

【讨论】:

  • 不完全是。再举一个例子,假设我正在编写一个“C”解析器。我已经整理好了我的 lex 部分。现在我想写 yacc 部分。我现在必须编写许多规则来将“C”可以是的所有东西放在一起。如果我想先写下 switch 语句的规则。当我改进 switch yacc 规则时,如何编写一个临时捕获所有规则或规则来处理可能在“C”源文件中的所有其他内容。换句话说,如何开发 yaccer。书中的所有示例都显示了完整的 yacc 规则。
  • 当你实现了一种语言的一个子集时,剩下的要实现的实际上暂时是无效的语法。这就是为什么它需要通过错误处理例程来处理。 Lex 的工作是将字符流转换为令牌流,并且有一个 catch all 规则来按原样传递字符是有意义的。但是 Yacc 的工作是为给定的语法做一些有意义的事情。如果未定义语法,则 Yacc 无法进行有意义的操作。让我这样问:如果“catch all”规则是可能的,你想做什么?
  • 我想捕捉我现在没有做的所有其他事情。所以如果我有 5 条规则要写。我按照第一条规则工作,直到该规则生效。然后我处理规则二等。当我处理规则时,我不希望 yyerror 触发我没有为其编写规则的所有令牌。当我目前正在开发的任何规则再次不起作用时,应该触发 yyerror。我想知道如何从使用全部捕获的零规则到编写的所有规则而不是全部捕获,因为我所有的规则编写都在处理所有令牌。感谢您耐心解答我的问题。
【解决方案3】:

打印与 yacc 中任何规则都不匹配的标记并继续解析的方法可能是在您的 yacc 文件中添加此规则:

| error  {
    char *text;
    $<symbol_table>$->cb = malloc(sizeof(struct code_block));
    text = strdup(yytext);
    $<symbol_table>$->cb->function_call= text;
    $<symbol_table>$->cb->pos =yylineno;
    *yytext=NULL;
    printf("error: %s at line no %d\n",$<symbol_table>$->cb->function_call,$<symbol_table>$->cb->pos);**
         }

【讨论】:

  • 谢谢。这看起来很有趣
猜你喜欢
  • 2013-01-13
  • 2018-10-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-04
  • 1970-01-01
  • 2011-07-23
  • 2011-02-12
相关资源
最近更新 更多