我有兴趣将Google Go的分号插入添加到我的flex文件中。
来自Go文档:
分号
与C一样,Go的正式语法使用分号来终止语句; 与C不同,这些分号不会出现在源代码中。而是 lexer使用一个简单的规则来自动插入分号 扫描,因此输入文本大部分都没有。
规则就是这样。如果换行符之前的最后一个标记是标识符 (包括像int和float64这样的单词),一个基本文字,如a 数字或字符串常量,或其中一个标记
break continue fallthrough return ++ -- ) }
词法分析器总是在令牌后插入分号。这可能是 总结为“如果新行出现在可能结束的令牌之后 声明,插入分号“。
在结束括号之前也可以省略分号,所以
之类的陈述go func() { for { dst <- <-src } }()
不需要分号。 Idiomatic Go程序仅在分号中有分号 诸如for循环子句之类的地方,用于分隔初始化程序, 条件和延续元素。他们也是必要的 如果您编写代码,则在一行上分隔多个语句 方式。
一个警告。你永远不应该把控件的开头括号 下一行的结构(if,for,switch或select)。如果你这样做, 分号将在大括号之前插入,这可能会导致 有害的影响。像这样写下
if i < f() { g() }
不喜欢这个
if i < f() // wrong! { // wrong! g() // wrong! } // wrong!
我将如何进行此操作(如何在流中插入令牌,如何查看匹配的最后一个令牌以查看它是否是一个好主意等等)?
我也在使用野牛,但Go似乎只是用他们的词法分析器插入分号。
答案 0 :(得分:5)
您可以通过在必要时插入分号的函数传递lexer结果标记。一旦检测到需要插入,下一个令牌就可以放回到输入流中,基本上在下一轮回复它。
下面是一个在换行符之前插入SEMICOLON的示例,当它跟随WORD时。野牛文件“insert.y”是这样的:
%{
#include <stdio.h>
void yyerror(const char *str) {
printf("ERROR: %s\n", str);
}
int main() {
yyparse();
return 0;
}
%}
%union {
char *string;
}
%token <string> WORD
%token SEMICOLON NEWLINE
%%
input:
| input WORD {printf("WORD: %s\n", $2); free($2);}
| input SEMICOLON {printf("SEMICOLON\n");}
;
%%
并且lexer是通过flex生成的:
%{
#include <string.h>
#include "insert.tab.h"
int f(int token);
%}
%option noyywrap
%%
[ \t] ;
[^ \t\n;]+ {yylval.string = strdup(yytext); return f(WORD);}
; {return f(SEMICOLON);}
\n {int token = f(NEWLINE); if (token != NEWLINE) return token;}
%%
int insert = 0;
int f(int token) {
if (insert && token == NEWLINE) {
unput('\n');
insert = 0;
return SEMICOLON;
} else {
insert = token == WORD;
return token;
}
}
输入
abc def
ghi
jkl;
打印
WORD: abc
WORD: def
SEMICOLON
WORD: ghi
SEMICOLON
WORD: jkl
SEMICOLON
输出非常量令牌需要一些额外的工作 - 我试图保持这个例子简单,只是为了给出这个想法。
答案 1 :(得分:1)
更改\n
和}
的词法分析器规则,以查看词法分析器返回的最后一个标记。这将要求您的词法分析器记录为每个规则返回的最后一个标记。
然后你的换行规则将如下所示:
\n { if (newline_is_semi(last_token)) {
return SEMICOLON;
}
}
newline_is_semi
将检查last_token是否在您列出的令牌列表中。
在结束括号之前处理可选分号:匹配'}'时检查last_token是否为SEMICOLON,如果没有输出'}'并返回SEMICOLON
'}' { if (last_token != SEMICOLON) {
unput('}');
return SEMICOLON;
}
}
答案 2 :(得分:0)
一种简单的方法是创建一个全局变量
Unauthorized
然后假设在 ")" 之后你想插入一个 SEMICOLON 然后你设置 ins_token = 1 并在其他令牌中你重置 ins_token = 0
现在,在 ")" 出现 "\n" 之后,检查 ins_token == 1 是否返回 SEMICOLON,否则忽略它并始终重置 ins_token = 0。
ins_token 充当标志。当您想要插入 SEMICOLON 时设置标志。在获取 \n 时,它将检查该标志,如果设置了它,它将插入分号。
这是因为 flex 不记得之前的标记。
%{
ins_token = 0
%}