如何在 yacc 或 bison 中实现 python 样式的缩进?

How to implement python style indentation in yacc or bison?

我一直在尝试在我的 bison 语法中实现 python 风格的缩进,一些关于该实现的见解或想法会很好。

最好的方法通常是让词法分析器跟踪缩进级别并将 INDENT/UNINDENT 标记适当地插入到标记流中。这是我必须执行的一些弹性代码:

%x LINESTART
%s NORMAL
%{
static std::stack<int> indent;
static int indent_depth(const char *);
%}

%%

<INITIAL>.*|\n          { yyless(0); BEGIN(LINESTART); indent.push(0); }
<LINESTART>[ \t]*       { int depth = indent_depth(yytext);
                          if (depth < indent.top()) {
                              indent.pop();
                              yyless(0);
                              return UNINDENT; }
                          BEGIN(NORMAL);
                          if (depth > indent.top()) {
                              indent.push(depth);
                              return INDENT; } }
<LINESTART>.            { yyless(0);
                          if (indent.top() > 0) {
                              indent.pop();
                              return UNINDENT; }
                          BEGIN(NORMAL); }
<LINESTART><<EOF>>      { if (indent.top() > 0) {
                              indent.pop();
                              return UNINDENT; }
                          BEGIN(NORMAL); }
<LINESTART>[ \t]*\n     { lineno++; }
<LINESTART>[ \t]*#.*\n  { lineno++; }
[[({]                   { parens++; return *yytext; }
[])}]                   { if (--parens < 0) parens = 0;
                          return *yytext; }
\n                      { lineno++;
                          if (parens == 0) BEGIN(LINESTART); }

这段代码在特殊情况下有些棘手——例如,您需要忽略空行和只有注释的行,并且您可能还想忽略不平衡括号内的缩进(上面的代码就是这样做的)。