对于所有编译器专家,我想编写一个递归下降解析器,只使用代码。不要从其他语法生成词法分析器和解析器,也不要告诉我读《龙书》,我最终会来处理它的。
我想深入了解实现一个适用于一个相对简单的语言(比如CSS)的词法分析器和解析器的细节。我想做到这一点。这可能最终会成为一系列问题,但现在我从词法分析器开始。可以在这里找到CSS的标记化规则。
我发现自己写出了像这样的代码(希望您能推断出其余部分):
我应该称之为什么?离合理的东西还有多远?我试图平衡一些在效率和易于使用方面公平的东西,使用堆栈来实现某种状态机非常有效,但我不确定如何继续下去。
我有一个输入流,可以每次读取1个字符。我现在不做任何向前查看,只是读取字符,然后根据当前状态尝试做一些事情。
我真的很想进入编写可重用代码片段的思维模式。这个“Transition”方法目前就是这样做的,它将弹出堆栈的当前状态,然后以相反的顺序推送参数。这样,当我编写“Transition(ParserState.SubIdent,ParserState.Init)”时,它将“调用”子例程“SubIdent”,完成后返回到“Init”状态。
解析器将以类似的方式实现,当前,像这样将所有内容放在一个单独的大方法中使我能够轻松返回标记,但它也迫使我将所有内容都保留在一个单独的大方法中。是否有一种好的方法将这些标记化规则拆分成单独的方法?
我想深入了解实现一个适用于一个相对简单的语言(比如CSS)的词法分析器和解析器的细节。我想做到这一点。这可能最终会成为一系列问题,但现在我从词法分析器开始。可以在这里找到CSS的标记化规则。
我发现自己写出了像这样的代码(希望您能推断出其余部分):
public CssToken ReadNext()
{
int val;
while ((val = _reader.Read()) != -1)
{
var c = (char)val;
switch (_stack.Top)
{
case ParserState.Init:
if (c == ' ')
{
continue; // ignore
}
else if (c == '.')
{
_stack.Transition(ParserState.SubIdent, ParserState.Init);
}
break;
case ParserState.SubIdent:
if (c == '-')
{
_token.Append(c);
}
_stack.Transition(ParserState.SubNMBegin);
break;
我应该称之为什么?离合理的东西还有多远?我试图平衡一些在效率和易于使用方面公平的东西,使用堆栈来实现某种状态机非常有效,但我不确定如何继续下去。
我有一个输入流,可以每次读取1个字符。我现在不做任何向前查看,只是读取字符,然后根据当前状态尝试做一些事情。
我真的很想进入编写可重用代码片段的思维模式。这个“Transition”方法目前就是这样做的,它将弹出堆栈的当前状态,然后以相反的顺序推送参数。这样,当我编写“Transition(ParserState.SubIdent,ParserState.Init)”时,它将“调用”子例程“SubIdent”,完成后返回到“Init”状态。
解析器将以类似的方式实现,当前,像这样将所有内容放在一个单独的大方法中使我能够轻松返回标记,但它也迫使我将所有内容都保留在一个单独的大方法中。是否有一种好的方法将这些标记化规则拆分成单独的方法?