Parsing 一组最简单的lex/yacc规则,用于提取类似函数调用的语句

Parsing 一组最简单的lex/yacc规则,用于提取类似函数调用的语句,parsing,yacc,lex,Parsing,Yacc,Lex,我在lex/yacc方面没有实际经验,所以我的问题可能看起来很幼稚,但我无法利用在stackoverflow和internet中找到的所有信息找到合理的解决方案。假设我需要一个类似C/C++语法的解析器,但我需要的只是类似函数调用的语句,比如foo(a)、bar(1,2)、foobar(“x”,a,(b,C)),等等。我对代码和表达式的有效性不感兴趣;我准备把它们看作是文字或符号序列。我需要识别逗号和括号之间的字符串文字、标识符和表达式(只是一系列符号)。嗯,我需要删除注释并识别预处理器指令,这

我在lex/yacc方面没有实际经验,所以我的问题可能看起来很幼稚,但我无法利用在stackoverflow和internet中找到的所有信息找到合理的解决方案。假设我需要一个类似C/C++语法的解析器,但我需要的只是类似函数调用的语句,比如foo(a)、bar(1,2)、foobar(“x”,a,(b,C)),等等。我对代码和表达式的有效性不感兴趣;我准备把它们看作是文字或符号序列。我需要识别逗号和括号之间的字符串文字、标识符和表达式(只是一系列符号)。嗯,我需要删除注释并识别预处理器指令,这超出了问题的范围

我对lex/yacc不太熟悉,但我是一名软件工程师,有一些经验。过去,我在C++中编写了这样的解析器,没有任何第三方助手/工具。五分钟内不会,但我不会说这有什么大不了的。然而,这是一段需要管理的代码。所以下次我需要它时,我认为使用lex/yacc是个好主意。毫无疑问,使用专门用于语法的工具,这样一个基本任务的解决方案应该更加基本。显然,我花了更多的时间(没有成功)试图从lex/yacc获得一些东西,而不是完全手动编写解析器

假设我的lex生成标识符、字符串文字、“、”(“、”)和符号(所有其他)。它删除注释和预处理器内容。所以我想在yacc中说

expression_element
  : IDENTIFIER
  | STRING_LITERAL
  | SYMBOL
  | list_expression
  ;

list_expression
  : '(' ')'
  | '(' expression ')'
  | '(' expression_list ')'
  ;

expression_list
  : expression ',' expression
  | expression_list ',' expression
  ;

expression
  : expression_element
  | IDENTIFIER list_expression
  { /* And this is what I really need. */ }
  | expression expression_element
  ;
我相信这可以用另一种方式写,也许更简单。正如我所说,我不介意表达的有效性,我只在乎它们关于“,”,“(“and”)和简单性的完整性。现在,我无法解决的真正问题是:无论我做什么,我都不能强迫他们区分“标识符列表表达式”(优先)和“标识符非列表表达式”,其中第一个是我需要的类似函数调用的语句,第二个只是标识符本身作为任何其他内容(语句)的一部分。我尝试的任何操作都只会导致冲突和后续解析错误


有什么简单的东西我错过了吗?还是我需要为这么少的员工制定一套血淋淋的语法?或者我只需要另一个工具(推荐?)?我宁愿避免自己编写解析器,除非这是唯一简单的解决方案…

您可以通过将
|IDENTIFIER list_expression
移动到
expression_element
并添加

%left IDENTIFIER
%left '('
在开场白中,为了强制
标识符列表\表达式
优先于将
标识符
列表\表达式
串联,作为
表达式
的一部分

在优先级声明中使用
%left
完全是任意的,因为这里的关联性是无关的。优先级声明仅用于解决歧义,而对
标识符标识符
的解析并不含糊;在这两种情况下,只能进行一次解析。这仅适用于
标识符的情况(
存在歧义:这可能是右侧
标识符列表表达式的开始,也可能是一个
表达式元素
,由
标识符
后跟一个
表达式元素
,由
列表表达式
组成。要强制进行第一次解释,我们必须编辑以确保歧义得到解决,从而有利于移动

在没有相关优先声明的情况下,yacc/bison将解决有利于shift操作的歧义。但它也会产生一个警告。因为优先声明会产生相同的默认操作,所以生成的解析器在修改或不修改的情况下都是相同的;声明的唯一效果是抑制警告信息


我不知道这是否真的是你的问题的答案,因为没有足够的细节来知道你实际要解决的问题。如果你正在查看的程序代码是C,你会发现
(函数)(3)形式的表达式
将不会被识别为函数调用,尽管它们很可能是(它们很可能是强制转换表达式;这取决于括号内内容的语义)使用这种形式的函数调用是为了避免调用类似于函数的同名宏,但它们也可能仅用于满足编码器的特定语法美学。如果没有大量的解析基础设施,则无法区分强制转换和函数调用(例如,您需要解析
typedef
声明,至少要弄清楚别名的名称)。

您可以通过将
|IDENTIFIER list_expression
移动到
expression_元素
并添加

%left IDENTIFIER
%left '('
在开场白中,为了强制
标识符列表\表达式
优先于将
标识符
列表\表达式
串联,作为
表达式
的一部分

在优先声明中使用
%left
完全是任意的,因为这里的关联性是无关的。优先声明仅用于解决歧义,并且对
标识符和
进行解析(
没有歧义;在这两种情况下,只有一种解析是可能的。这只适用于
标识符的情况(
存在歧义:这可能是右侧
标识符列表\表达式的开始,也可能是一个
表达式\元素
,由
标识符
后跟一个
表达式\元素
,由
列表\表达式
组成,以强制第一个解释