【发布时间】:2017-03-03 23:37:49
【问题描述】:
我一直在使用对空格敏感的词法分析器和解析器来实现类似 Python 的语法。主要目标是了解解析器和词法分析器。
到目前为止,我的想法是在词法分析器阶段使空格无关紧要。例如,下面的输入将导致下面的输出。
if x:
x
else:
y
变成:
if x :{ x}; else :{ y};
我遇到的问题是,我不确定这对于规范解决方案是否是好的输出。人们会期望输出如下所示;一个表达式。
if x:{x} else:{y};
我也有一个解析器,但它不处理显示的输出,因为它不希望在结果和替代之间有分号。
我目前解决这个问题的想法如下:
1) 预处理令牌流并将if e: {e}; else: {e}; 形式的每个表达式转换为if e: {e} else: {e},但这似乎是一个严重的hack。
2) 在解析器阶段,我可以定义if 表达式在后件体之后有一个分号。但这对我来说似乎很难看,因为如果我也想解析单行 if's,我的解析器中的那些 if 表达式也需要另一种情况。规则看起来类似于我的解析器中显示的规则。
IF ::= if Expr : Expr else : Expr;
| if Expr : Expr; else : Expr;
我的问题是,lex 和解析空格敏感语言的规范方法是什么?我的方法是完全错误的,还是没有办法绕过我目前的输出?
lex.x
%{
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#define MAX_DEPTH 10
int nesting = 0 ;
unsigned int indent_stack[MAX_DEPTH] ;
unsigned int first[MAX_DEPTH] = { 1 };
unsigned int level = 0 ;
void process_indent(char* line) ;
%}
PUNCT [-+*/=<>:]*
ID [A-Za-z_][A-Za-z0-9_]*
INT [0-9]+
%option noyywrap
%%
^[ ]*\n {/* Ignore blank lines. */}
^[ ]*[^ \n]+ {int last = yyleng - 1;
process_indent(yytext) ;
while ((last >= 0) &&
(yytext[last] != ' ')) {
unput(yytext[last]);
last-- ;}}
"(" {printf(" "); ECHO; nesting++ ; }
")" {printf(" "); ECHO; nesting-- ; }
{ID}|{INT}|{PUNCT} {printf(" ") ; ECHO;}
[ \r] {}
\n {}
<<EOF>> { process_indent("EOF") ; return 0 ; }
%%
unsigned int white_count(char* line) {
unsigned int count = 0 ;
while (*line == ' ')
count++, line++ ;
return count ;
}
void process_indent(char* line) {
unsigned int indent = white_count(line) ;
if (nesting)
/* Ignore indents while nested. */
return ;
if (indent == indent_stack[level]) {
if (!first[level])
printf(" ;") ;
first[level] = 0 ;
return ;
}
if (indent > indent_stack[level]) {
printf("{") ;
level = level + 1;
indent_stack[level] = indent ;
first[level] = 0;
return ;
}
while (indent < indent_stack[level]) {
level = level -1;
if(level > 0)
printf(" };") ;
else
printf("};");
}
assert(level >= 0) ;
}
int main(int argc, char* argv[]) {
indent_stack[0] = 0 ;
yylex() ;
printf("\n") ;
}
```
【问题讨论】: