我是词法分析的新手,如果标题不够清楚,请您谅解。
基本上,我正在使用Jison解析一些文本,并且试图使词法分析器理解缩进。这是有问题的:
(\r\n|\r|\n)+\s* %{
parser.indentCount = parser.indentCount || [0];
var indentation = yytext.replace(/^(\r\n|\r|\n)+/, '').length;
if (indentation > parser.indentCount[0]) {
parser.indentCount.unshift(indentation);
return 'INDENT';
}
var tokens = [];
while (indentation < parser.indentCount[0]) {
tokens.push('DEDENT');
parser.indentCount.shift();
}
if (tokens.length) {
return tokens;
}
if (!indentation.length) {
return 'NEWLINE';
}
%}
到目前为止,几乎所有功能都可以按预期进行。一个问题是我尝试返回
DEDENT
标记数组的行。看来Jison只是将数组转换为字符串,这导致我得到诸如Expecting ........, got DEDENT,DEDENT
之类的解析错误。我希望能解决此问题的方法是手动将一些
DEDENT
令牌推入堆栈。可能具有this.pushToken('DEDENT')
之类的功能或类似的功能。但是Jison文档不是很好,我可以使用一些帮助。有什么想法吗?
编辑:
在查看生成的解析器代码之后,我似乎已经能够解决此问题。这似乎是可行的...
if (tokens.length) {
var args = arguments;
tokens.slice(1).forEach(function () {
lexer.performAction.apply(this, args);
}.bind(this));
return 'DEDENT';
}
这使词法分析器对堆栈中的每个
DEDENT
使用完全相同的输入来执行另一个操作,从而允许其添加适当的下标。但是,这感觉很糟糕,我担心可能会出现无法预料的问题。如果有人对更好的方法有任何想法,我仍然会喜欢。
最佳答案
几天后,我终于找到了一个更好的答案。看起来是这样的:
(\r\n|\r|\n)+[ \t]* %{
parser.indentCount = parser.indentCount || [0];
parser.forceDedent = parser.forceDedent || 0;
if (parser.forceDedent) {
parser.forceDedent -= 1;
this.unput(yytext);
return 'DEDENT';
}
var indentation = yytext.replace(/^(\r\n|\r|\n)+/, '').length;
if (indentation > parser.indentCount[0]) {
parser.indentCount.unshift(indentation);
return 'INDENT';
}
var dedents = [];
while (indentation < parser.indentCount[0]) {
dedents.push('DEDENT');
parser.indentCount.shift();
}
if (dedents.length) {
parser.forceDedent = dedents.length - 1;
this.unput(yytext);
return 'DEDENT';
}
return `NEWLINE`;
%}
首先,我修改了捕获正则表达式,以确保在一系列非换行符空格之后,我不会无意间捕获额外的换行符。
接下来,我们确保有2个“全局”变量。
indentCount
将跟踪我们当前的缩进长度。如果forceDedent
的值大于0,则会迫使我们返回DEDENT
。接下来,我们有一个条件来测试
forceDedent
上的真实值。如果有一个,我们将其递减1并使用unput
函数以确保我们至少在同一模式上重复至少一次,但是对于此迭代,我们将返回一个DEDENT
。如果尚未返回,则得到当前缩进的长度。
如果当前缩进大于我们最近的缩进,我们将在
indentCount
变量上进行跟踪并返回INDENT
。如果我们还没有回来,那么是时候准备迎接可能的下垂了。我们将创建一个数组来跟踪它们。
当我们检测到一个凹陷时,用户可能试图一次关闭全部1个或更多块。因此,我们需要为用户关闭的块包含一个
DEDENT
。我们建立一个循环,并说只要当前缩进小于我们最近的缩进,我们就会在列表中添加一个DEDENT
并将一个项目移出indentCount
。如果我们跟踪了任何下位字符,则需要确保所有这些下位字符都被词法分析器返回。因为词法分析器一次只能返回1个令牌,所以我们在这里将返回1,但是我们还将设置
forceDedent
变量以确保我们也返回其余的令牌。为了确保我们再次迭代该模式并且可以插入这些凹坑,我们将使用unput
函数。在任何其他情况下,我们都将返回
NEWLINE
。关于javascript - 如何使用Jison lexer返回多个 token ,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/40189324/