Compiler construction 柔性标识线末端

Compiler construction 柔性标识线末端,compiler-construction,flex-lexer,Compiler Construction,Flex Lexer,我们正在尝试更正词法分析解析器中的一个错误。我们正在使用flex,并且我们必须支持多行字符串。问题是,当字符串的结尾与开头不在同一行时,我们不计算新行。我们有两种情况,即换行符的结尾和\n从程序员那里插入到字符串中。是否有办法了解行尾,并以某种方式在规则中对其进行计数?如果使用%option yylineno,flex将在变量yylineno中为您保留行尾计数。只要你不调用输入,它就会正确 有两个小问题: yylineno的值对于读取的最后一个字符是正确的,这是令牌中的最后一个字符。但是,如果您

我们正在尝试更正词法分析解析器中的一个错误。我们正在使用flex,并且我们必须支持多行字符串。问题是,当字符串的结尾与开头不在同一行时,我们不计算新行。我们有两种情况,即换行符的结尾和\n从程序员那里插入到字符串中。是否有办法了解行尾,并以某种方式在规则中对其进行计数?

如果使用%option yylineno,flex将在变量yylineno中为您保留行尾计数。只要你不调用输入,它就会正确

有两个小问题:

yylineno的值对于读取的最后一个字符是正确的,这是令牌中的最后一个字符。但是,如果您有多行标记,通常还需要知道标记开头的行号;您需要将yylineno的值存储在上一个标记的末尾

幸运的是,您可以将宏YY_USER_ACTION定义为一些C代码;这将插入到每个操作的开头,包括没有任何显式操作的规则。这样做可以确保前一个值始终作为yylineno_start可用:

定义YY_用户_操作\ yylineno_start=yylineno_已保存\ yylineno_saved=yylineno; 当然,您还需要声明这些变量

Flex不跟踪列位置。但也许你不介意。否则,您可以向上面提到的YY_USER_操作添加更多代码。简单的方法是保存字符总数,并在当前行的末尾记录字符总数。易于维护字符总数;每次只需添加yyleng的值。要在行首保持计数,需要检查yylineno的值是否更改,如果更改,则在标记中向后搜索以查找最后一个换行符。这听起来效率很低;大多数情况下,扫描时间很短

示例代码 以下是仅使用行号跟踪的最小解决方案:

%选项yylineno %选项noinput nounput noyywrap nodefault %{ int yylineno_saved=1; 定义YY_用户_操作\ yylineno_start=yylineno_已保存\ yylineno_saved=yylineno; %} %% int YYLINE无需启动; [[:space:][]//忽略包含换行符的空格 [[:digit:]+{printfindeger%s在第%d行\n,yytext,yylineno;} \\\.|\n |[^\\]*\{printfString从第%d行到第%d行\n, yylineno_开始,yylineno; } . // 忽略其他一切 %% int main argc,字符**argv{ 返回yylex; } 这是一个更复杂的方法,它也可以跟踪角色的位置,正如上面第2点所建议的。这一个使用yylloc全局变量,这是向bison传递完整令牌边界的常用方式。请注意,此代码不会与较少或较多的用户协作。如果您使用这些特性,您将需要为它们编写包装

%选项yylineno %选项noinput nounput noyywrap nodefault %{ /*以下内容通常由bison生成,如果 *在bison定义中启用位置跟踪。 */ 结构YYLTYPE{ int第一条线; int第一列; int最后一行; int最后一列; }; 结构YYLTYPE yylloc={1,1,1}; /*我们还需要保持绝对字符位置,以及 *位置在当前行的开头。 */ int char_位置=0; int line_start=0; 定义YY_用户_操作\ 字符位置+=yyleng\ 如果yylineno!=yylloc.last_行{\ char*p=yytext+yyleng\ 行\开始=字符\位置\ 而*-p!='\n'-line\u开始\ } \ yylloc.first_行=yylloc.last_行\ yylloc.first_列=yylloc.last_列\ yyloc.last_line=yylineno\ yyloc.last_column=字符位置-行开始+1; /*只是作秀*/ void show_与_locconst char*msg{ printf[%d:%d->%d:%d]%s, yylloc.first_行,yylloc.first_列, yylloc.last_行,yylloc.last_列, 味精; } %} %% [[:space:][]//忽略包含换行符的空格 [[:digit:][+{show_with_locInteger\n;} \\\.|\n |[^\\]*\{show_with_locString\n;} . // 忽略其他一切 %% int main argc,字符**argv{ 返回yylex; }
您可以在Flex中使用的概念

每当遇到双引号时,启动一个名为的状态。 在状态内部,您可以编写不同的规则集,例如-当您在字符串中得到一个反斜杠,后跟一个新行时,您就知道它是一个多行字符串。您还可以在状态中单独检测换行符。 收到另一个双引号后,结束状态并返回状态。 源代码:string.l


我尝试了您建议的方法,但没有任何效果。问题是,当解析字符串的规则使用字符时,yylineno不会递增,我的问题是,有没有办法区分行尾和程序员在yytext中编写的\n?@george:程序员编写的是什么意思?听起来您正在做一些不寻常的事情,在这种情况下,您必须显示您的代码。我的意思是源文件可能是这样的:hello我的名字是george\n EOL EOL是实际的行尾,\n是字符串格式如何区分差异?字符串\\\.\.\[^\\]*\这是多行的规则strings@GeorgeXanthakis:%选项yylineno仅识别换行符\n是两个字符,一个反斜杠和一个n。那不是一个换行符。我不知道为什么%option yylineno不适合你;您必须实际发布一个。@GeorgeXanthakis:如果问题是我刚刚修复的答案中的一个小而明显的错误,那么如果您提到错误消息,而只是说什么都不起作用,那会很有帮助:
%option noyywrap

%x STRING

%{    
int line_count = 1;
%}

%%

\"   {
                printf("%d: String started\n", line_count);
                BEGIN(STRING);
     }

<STRING>"\\\n"  { line_count++; }


<STRING>\"  {
                printf("%d: String ended\n", line_count);
                BEGIN(INITIAL);
            }

<STRING>"\\n"  { 
                printf("new line\n");
            }                   

<STRING>.   {   
                printf("%s\n", yytext);
            }


\n          { line_count++; }

.           {}



%%
int main(int argc,char *argv[]){
    yyin = fopen(argv[1], "r");      // taking input from a file
    yylex();
    printf("\nTotal Lines: %d\n", line_count);
    return 0;
}
"single line" 
"multi\
line"