Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/371.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 让我把话说清楚:解析是什么?_Java_Parsing_Scheme - Fatal编程技术网

Java 让我把话说清楚:解析是什么?

Java 让我把话说清楚:解析是什么?,java,parsing,scheme,Java,Parsing,Scheme,昨天我问了语法,今天在Java中,我学习如何使用我完成的词法分析器中的标记实现语法解析算法 对于这个问题,我需要一个人来检查我的理解 假设给定Scheme语法: exp -> ( rest | #f | #t | ' exp | integer_constant | string_constant | identifier rest -> ) | exp+ [ . exp ] ) 下面的伪代码正确吗?我研究了递

昨天我问了语法,今天在Java中,我学习如何使用我完成的词法分析器中的标记实现语法解析算法

对于这个问题,我需要一个人来检查我的理解

假设给定Scheme语法:

exp -> ( rest
     | #f
     | #t
     | ' exp
     | integer_constant
     | string_constant
     | identifier

rest -> )
     | exp+ [ . exp ] )
下面的伪代码正确吗?我研究了递归下降解析器,需要通过创建解析树的节点为解释器创建一个解析树

 Node parseExp() {
      check to see if the token is left parenthesis
           if true, return a node for Cons (which is a non-terminating node in Scheme 
           parse tree) and call parseRest()
      else check to see if the token is #f
           if true, return a node for Boolean with stored value #f
      else check to see if the token is #t
           if true, return a node for Boolean with stored value #t
      else check to see if the token is quote
           if true, return a node for Quote and recursively call parseExp()
      else check to see if the token is integer_constant
           if true, return a node for Integer with stored value int
      else check to see if the token is string_constant
           if true, return a node for String with stored string value
      else check to see if the token is identifier
           if true, return a node for identifier with stored string value
      else
           print error message saying a Syntax error occured
           return null
 }

 Node parseRest() {
      check to see if the token is right parenthesis
           if true, return a node for Nil (which is a terminating () node in scheme 
           parse tree)
      else  // I am having difficulty trying to put this into an algorithm here
           call parseExp() for the first expression
           while (token does not equal right parenthesis) {
                getNextToken()
                if (token equals right parenthesis)
                     return a node for right parenthesis
                else if (token equals dot)
                     return a node for dot
                     getNextToken()
                     if (token equals right parenthesis)
                          print error message saying a Syntax error occurred
                          return null
                     else
                        call parseExp()
                else
                     parseExp() 
           }    
 }
如果我有一个错误的想法,请纠正我。parseRest()据说需要一个先行标记才能做出决定,这可以解释一下吗?可能是一个伪代码示例


谢谢

你的思路是对的,但有一些问题:

check to see if the token is left parenthesis
     if true, return a node for Cons (which is a non-terminating node in Scheme 
     parse tree) and call parseRest()
这有点模棱两可,因为您没有提到打算对
parseRest()
的结果执行什么操作,但我假设您希望将其存储在Cons节点中。问题是Cons节点应该有两个子节点(如果列表是列表的头和尾-如果不清楚,您可能需要查看Scheme语言的规则),但是parseRest只提供一个节点,所以这不起作用。因此,让我们后退一步,想想当我们看到<代码>时,我们想要什么(< /代码>:

是一对的开头(即点对或非空列表),或者是空列表
()
。在第一种情况下,我们需要一个Cons节点,但在第二种情况下,我们需要一个Nil节点,因为空列表不是Cons单元格。因此,我们有两种可能性,在查看列表的其余部分之前,我们不知道要选择哪一种。因此,不应该在这里做出决定,而应该在parseRest函数中做出决定。因此,我们更改了代码致:

check to see if the token is left parenthesis
     if true, return the result of parseRest()
现在让我们看看parseRest:

在这里,您有时会返回点和圆括号的节点,但这些节点根本不应该是AST中的节点——它们是标记。另一个问题是,当您递归调用parseRest时,您仍然不清楚要对结果执行什么操作。有人可能认为您要返回结果,但while循环将是pointless,因为您每次都在第一次迭代中返回。事实上,即使在非递归的情况下,这也是一个问题:例如,您返回一个点节点,然后继续解析它之后的表达式。但是在返回之后,函数退出,因此返回之后的任何内容都将被忽略。因此,这不起作用

在讨论如何使其工作之前,让我们首先更清楚地了解生成的AST应该是什么样子:

  • 对于“()”我们需要一个Nil节点。这对您当前的代码很好
  • 对于“(x)”我们需要
    Cons(Ident(“x”),Nil)
  • 对于“(x.y)”我们需要
    Cons(Ident(“x”),Ident(“y”)
  • 对于“(xy)”我们需要
    Cons(Ident(“x”)、Cons(Ident(“y”)、Nil))
  • 对于“(xy.z)”我们需要
    Cons(Ident(“x”)、Cons(Ident(“y”)、Ident(“z”))
我希望模式现在已经很清楚了(否则您可能需要查看Scheme语言),那么我们如何获得这种AST呢

好的,如果我们看到一个
,我们返回
Nil
。这在你的代码中已经起作用了。否则我们解析一个表达式(如果这里没有有效的表达式,我们就有一个错误)。接下来会发生什么?如果我们找到一个表达式,该表达式是Cons单元格的第一个元素。所以我们想返回
Cons(表达式,…)
。但是,
部分包含什么?这取决于下一个标记是否是点。如果它是点,我们有一个点表达式,因此点后需要有一个表达式,我们希望返回
Cons(点前表达式,点后表达式)
。如果没有点,则表示我们在一个列表中,下面是它的尾部。因此,我们希望返回
Cons(表达式,parseRest())

parseRest()据说需要一个先行标记才能做出决定,这可以解释一下吗?可能是一个伪代码示例

Lookahead意味着您必须查看下一个令牌,而不实际将其从流中删除。就伪代码而言,这意味着您希望知道在调用
nextToken()
时将返回哪个令牌,而不实际更改下一次对
nextToken()的调用
将返回。因此您将拥有另一个内置函数,如
peek next()
,该函数返回下一个令牌,而不实际推进令牌流中的迭代器


在parseRest中需要它的原因是点:当你检查下一个标记是否是点,结果发现不是,那么你就不希望该标记实际消失。也就是说,你将调用parseExpression,然后parseExpression将调用nextToken,对吗?当这种情况发生时,你希望它返回正确的标记在当前表达式之后-您不想跳过该标记,因为您必须检查它是否为点。因此,在检查该点时,您需要调用
peek标记
,而不是
nextToken
(当标记为点时,您仍然需要删除该标记).

编写正则表达式并通过
string.matches(…)测试输入是否更容易
?当然可以,但我正在用Java为scheme构造一个编译器。它需要提供错误检查。解析后的下一部分是构造解释器,解释器需要一个数据结构,如解析树。@Hannes Java正则表达式不支持递归,即使它们支持递归,也要编写这样一个monster regex很可能不会比这更容易(而且肯定不会更可读或更易于维护)。通常,用正则表达式解析上下文无关语言是不明智的(在Java中甚至不可能)。当然,即使您有这样一个正则表达式,它也会