如何描述识别通配符标识符的 lex 或 yacc 规则?

How to describe a lex or yacc rule to recognize wildcard identifier?

待解析的文本中有这样的文件系统相关命令的例子

infile abc*.txt
list abc*ff.txt

其中 abc*.txt 类似于 shell 命令的通用通配符参数。

不过,也有这样的数学表达式:

x=a*b

一个常见的表达式规则(在 yacc 文件中)是这样的:

expression: 
    expression '+' expression { $$ =  + ;  }
    |   expression '-' expression { $$ =  - ; }
    |   expression '*' expression { $$ =  * ; }
    ;

* 用作乘法运算符。

识别带 * 的令牌 IDENTIFIER 的规则如下:

[A-Za-z][A-Za-z0-9_\.\*]*   {
    yylval.strval = strdup(yytext);  return IDENTIFIER; }

对于infile或list等文件系统命令相关的语法,如开头的,后面的token会被当作IDENTIFIER,可能会有*作为通配符来匹配文件名。

但是对于像

这样的表达式
x = a*b

这应该是一个表达式,但在上面的 lex 规则中,a*b 将被视为一个 IDENTIFIER。它变成了将标识符 a*b 的值赋给 x.

如何在lex或yacc中保持表达式的语法规则并添加通配符文件名?

在 flex 中,这一切都可以通过使用所谓的 Start Conditions 来处理,并且在手册中有很好的描述,示例与您的要求相似。

我做了一个小示例词法分析器来演示这个工作:

ws [ \t\n\r]+
%s FILENAME
%%
{ws}    ; /* skip */
<<EOF>>    ;
<INITIAL>infile      BEGIN(FILENAME); 
<INITIAL>list         BEGIN(FILENAME); 
<FILENAME>[A-Za-z][A-Za-z0-9_\.\*]*     BEGIN(INITIAL);  
"*"               return(yytext[0]);
"+"               return(yytext[0]);
"-"               return(yytext[0]);
"/"               return(yytext[0]);
[A-Za-z][A-Za-z0-9_]*              return((int)("I"));
.                 printf("Bad character %c\n",yytext[1]);

我可以在调试模式下执行以显示其操作:

C:\Users\Brian>flex -d  SOwildcard.l    
C:\Users\Brian>gcc -o SOwildcard.exe lex.yy.c -lfl    
C:\Users\Brian>SOwildcard
--(end of buffer or a NUL)
a + b
--accepting rule at line 13 ("a")
--accepting rule at line 4 (" ")
--accepting rule at line 10 ("+")
--accepting rule at line 4 (" ")
--accepting rule at line 13 ("b")
--(end of buffer or a NUL)
infile a*.txt
--accepting rule at line 4 ("
")
--accepting rule at line 6 ("infile")
--accepting rule at line 4 (" ")
--accepting rule at line 8 ("a*.txt")
--(end of buffer or a NUL)
variable * identifier
--accepting rule at line 4 ("
")
--accepting rule at line 13 ("variable")
--accepting rule at line 4 (" ")
--accepting rule at line 9 ("*")
--accepting rule at line 4 (" ")
--accepting rule at line 13 ("identifier")
--(end of buffer or a NUL)  
list a*.*
--accepting rule at line 4 ("
")
--accepting rule at line 7 ("list")
--accepting rule at line 4 (" ")
--accepting rule at line 8 ("a*.*")
--(end of buffer or a NUL)
--accepting rule at line 4 ("
")
-^C

我知道你问过 lex,但我只有 flex。可能是相似的。