【问题标题】:Techniques for parsing code blocks without curly braces解析没有花括号的代码块的技术
【发布时间】:2019-05-16 03:38:57
【问题描述】:

我正在从头开始用 C# 编写一个简单的解析器/解释器(没有第三方库)。它编译为字节码,然后我有运行字节码的类。我快要结束了。我刚刚实现了while 和for 循环,并且正在处理if|else if|else 块。

就目前而言,我的解析器要求所有这些结构都使用花括号。我想让它更像 C,并且当块只包含一个语句时,花括号是可选的。这给我带来了麻烦。

if (condition)
{
    // Make curly braces optional when there is just one statement here
}

问题在于跟踪状态。解析器如何知道没有花括号的块何时结束。一种方法是检查在每个语句之后是否有一个没有大括号的块有效。但是,有很多不同的场景可以构成一个声明,因此这些检查需要在许多地方进行。这对我来说有点脆弱。

我只是想知道是否有人这样做并且知道在没有花括号时跟踪代码块何时结束的任何巧妙技巧。

【问题讨论】:

  • 你实现了什么样的解析器?语句和语句块的语法是什么样的?
  • @IanMercer:我只有一个词法分析器,它将源代码分解为标记,然后是一个解析器,它从上下文中找出字节码。我没有遵循任何特殊技术。该语言有点像 C,尽管这可能会改变。
  • @IanMercer:事实上,如果它更容易处理这个问题,我可能会更改语言。
  • 你能举一些很难判断一个块何时结束的例子吗?
  • @JimW:在任何情况下。正如我试图解释的那样,这意味着我需要在每条语句之后进行测试,并且并非所有语句都在同一个地方处理。所以这意味着在代码周围添加检查。任何这样的方法都很脆弱,因为您可能会错过一个地方或在更改代码时忘记添加一个地方。我只是想知道是否有人知道更巧妙的方法。

标签: c# parsing compiler-construction interpreter


【解决方案1】:

您需要查看recursive descent parser。它使创建解析器变得更加容易。假设您的语法如下所示:

statement
   : 'if' paren_expr ['{'] statement ['}'] 

paren_expr
   : '(' expr ')'

然后使用递归下降,您可以执行以下操作:

public void Statement()
{
    if(curToken == Token.If)
    {
       Eat(Token.If); // Eat is convenience method that moves token pointer on
       if(curToken == Token.LParen)
       {
          Eat(Token.LParen)
          ParenExpr();
          Eat(Token.RParen);
       }
       if(curToken == Token.LBrace) // this will signify a block of statements
       {   
          Eat(Token.LBrace);
          while(curToken != Token.RBrace)
             Statement();
          Eat(Token.RBrace);
       }
       else
          Statement();              
    }
}

public void ParenExpr()
{
   // do other token checks
}

为所有非终端执行此操作,您可以轻松构建 AST,然后您可以生成字节码。

【讨论】:

  • 那么,如果语句需要,Statement() 将通过再次调用自身来递归,这是否意味着?我确实考虑过调用一个例程来处理一个语句,但当然该语句可以是任何东西,包括其他 if 语句。所以可能会发生很多事情。但如果Statement() 是递归的,那么我想这没问题。
  • 顺便说一句,如果块有大括号和多个语句,您发布的代码似乎不起作用。这将如何运作?
  • 我没有关注你?你是说它不会解析if(condition){ if(condition2) doSomething(); if(condition3) doSometingElse()}?它会解析那个。
  • 不,我是说如果大括号之间有四个语句,它就不会解析。您拨打Statement() 一次。它将如何处理?
  • 好吧,你必须在方法的其余部分编写代码,它只会处理if,它也不会处理while,因为它是你的@的一个简单示例987654331@问题
猜你喜欢
  • 2012-01-18
  • 2016-12-18
  • 2010-12-25
  • 2017-04-07
  • 2011-04-07
  • 2020-03-26
  • 2015-12-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多