Parser和Lexer用于类似Python的语言

时间:2016-10-21 15:25:09

标签: c parsing lex

我一直在玩一个对空格敏感的词法分析器和解析器,用于类似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},但这似乎是一个严重的黑客攻击。

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") ;
}
```

1 个答案:

答案 0 :(得分:0)

我不了解规范,但我所做的是以某种方式计算空白(计算空格数,空格数/标签大小,标签数量或您选择的任何内容)然后将其作为另一位数据添加到每个标记,并在每个换行符上重置该计数。

然后当我解析东西时,我可以告诉我的if语句,以期望其缩进== if.indent等的其他语句。

我也曾经将缩进设为自己的令牌,这也可以。真的取决于你的语言有什么其他语法。