Java 中的递归下降解析器

2024-05-09

我想在序言中说这是我三年级编程语言课的家庭作业,我正在寻求一些帮助。我的作业如下:

截止日期:2013年2月22日晚上11点55分
提交:请将以下内容上传到CMS。

1. 源代码
2. 程序执行的屏幕截图,包括您使用的输入文件

使用您喜欢的任何编程语言编写递归下降解析器来解析由以下 EBNF 描述生成的语言。您的解析器应该检测输入程序是否有任何语法错误。它不必指定错误是什么以及错误在哪里。

<program>   begin <stmt_list> end
<stmt_list>  <stmt> {;<stmt_list>}
<stmt>    <assign_stmt> | <while_stmt>
<assign_stmt>  <var> = <expr>
<var>  identifier  (An identifier is a string that begins with a letter followed by 0     or more letters and digits)
<expr>  <var> { (+|-) <var>}           
<while_stmt>   while (<logic_expr>)  <stmt>
<logic_expr> ® <var> (< | >) <var>  (Assume that logic expressions have only less than     or greater than operators)

看起来很有趣的符号只是指向右侧的箭头。

我现在的问题比编程更符合逻辑:在我的第一次尝试中,我读入整个输入程序,将其保存到一个字符串中,然后解析该字符串并将每个符号转换为终端、expr 或其他符号你。

我最终发现这种方式行不通,因为,A:我不认为它是RDP,B:许多非终端由多于1个语句组成。

我放弃了这种方法,并决定在浪费更多时间编程之前,我将伪所有内容。我的新想法是为每个非终结符创建 1 个方法,然后逐个符号地解析输入字符串,希望在这些方法之间进行。这种方法看起来很合乎逻辑,但当我开始编写伪代码时,我对自己需要做什么感到非常迷失和困惑。我将如何完成这段代码?

以下是 RDP 的一些伪代码:

intputString;

public void parseProgram (Symbol.typeIsProgram) {
    if getNextSymbol == "begin" {
        if (intputString.substring (inputString.length()-3,
                inputString.length()) == "end") {
            Symbol stmt_lsit = new Symbol (intputString)
            parseStmt_list(stmt_list);              
        } else {
            Out "error, prog must end with end"
        }
    } else {
        Out "error, prog must begin with begin"
    }   
}

public void parseStmt_list (Stmbol.typeIsStmt_list) {
    symbol = getNextSymbol;
    if (Symbol.typeIsVar) {
        parseVar(symbol)
    } else if (Symbol.typeIsWhile)  {
        // weve only capture if the first word return is a while, we dont have the whole while statement yet
        ParseWhile_stmt(symbol)
    } else { }
}

public void parseStmt () { }
public void parseAssign_stmt () { }
public void parseVar () { }
public void parseExpr () { }
public void parseWhile_stmt () { }
public void parseLogic_expr () { }

public Symbol getNextSymbol() {
    //returns the next symbol in input string and removes it from the input string
}

仅供参考,我的解析器的示例输入程序是。

begin 
total = var1 + var2; 
while (var1 < var2) 
while ( var3 > var4)
var2 = var2 - var1 
end

根据这个特定的分配,可以以函数方式使用字符串处理。

尝试这个算法:

  1. 检查,该行以begin并以end
  2. 如果是 - 将剩余的字符串拆分为;并对每个部分(语句)执行以下步骤
  3. 检查语句是否包含= or while子串
  4. 对于分配检查,您可以将输入拆分为+ or -并针对每个部分检查可变条件(字母数字内容)
  5. 一会儿 - 检查( and )并递归处理括号之间及其之后的两个字符串
  6. 最后,对于按子字符串分割的逻辑表达式< or >,并检查零件是否是变量(字母数字)

也许,这不是非常灵活的解决方案,但据我所知,它对于您的任务来说是可以接受的。

EDIT:

我发现这个任务很有趣,并尝试编写一个完整的解决方案。

public enum Parser {
PROGRAM {
    void parse(String s) throws ParseException {
        s = s.trim();
        if (s.startsWith("begin") && s.endsWith("end")) {
            STATEMENT_LIST.parse(s.substring(5, s.length() - 3));
        } else {
            throw new ParseException("Illegal begin/end");
        }
    }
},

STATEMENT_LIST {
    void parse(String s) throws ParseException {
        String[] parts = s.trim().split(";");
        for (String part : parts) {
            STATEMENT.parse(part.trim());
        }
    }
},

STATEMENT {
    void parse(String s) throws ParseException {
        if (s.startsWith("while")) {
            WHILE.parse(s.substring(5));
        } else if (s.contains("=")) {
            ASSIGNMENT.parse(s);
        } else {
            throw new ParseException("Illegal statement: " + s);
        }
    }
},

WHILE {
    void parse(String s) throws ParseException {
        int i = s.indexOf("(");
        int j = s.indexOf(")");
        if (i != -1 && j != -1) {
            LOGICAL.parse(s.substring(i + 1, j).trim());
            STATEMENT.parse(s.substring(j + 1).trim());
        } else {
            throw new ParseException("Illegal while: " + s);
        }
    }
},

ASSIGNMENT {
    void parse(String s) throws ParseException {
        int i = s.indexOf("=");
        if (i != -1) {
            VARIABLE.parse(s.substring(0, i).trim());
            EXPRESSION.parse(s.substring(i + 1).trim());
        }
    }
},

EXPRESSION {
    void parse(String s) throws ParseException {
        String[] parts = s.split("\\+|-");
        for (String part : parts) {
            VARIABLE.parse(part.trim());
        }
    }
},

LOGICAL {
    void parse(String s) throws ParseException {
        int i;
        if (s.contains("<")) {
            i = s.indexOf("<");
        } else if (s.contains(">")) {
            i = s.indexOf(">");
        } else {
            throw new ParseException("Illegal logical: " + s);
        }

        VARIABLE.parse(s.substring(0, i).trim());
        VARIABLE.parse(s.substring(i + 1).trim());
    }
},

VARIABLE {
    void parse(String s) throws ParseException {
        if (!s.matches("^[a-zA-Z][a-zA-Z0-9]*$")) {
            throw new ParseException("Illegal variable: " + s);
        }
    }
};

abstract void parse(String s) throws ParseException;

public static void main(String[] args) {
    try {
        PROGRAM.parse("begin \n" +
                "total = var1 + var2; \n" +
                "while (var1 < var2) \n" +
                "while ( var3 > var4)\n" +
                "var2 = var2 - var1 \n" +
                "end");
        System.out.println("OK");
    } catch (ParseException e) {
        System.out.println(e.getMessage());
    }
}
}

class ParseException extends Exception {
public ParseException(String message) {
    super(message);
}
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java 中的递归下降解析器 的相关文章

  • Spring应用中Eureka健康检查的问题

    我正在开发一个基于 Spring 的应用程序 其中包含多个微服务 我的一个微服务充当尤里卡服务器 到目前为止一切正常 在我所有其他微服务中 用 EnableEurekaClient 我想启用这样的健康检查 应用程序 yml eureka c
  • 如何使用assertEquals 和 Epsilon 在 JUnit 中断言两个双精度数?

    不推荐使用双打的assertEquals 我发现应该使用带有Epsilon的形式 这是因为双打不可能100 严格 但无论如何我需要比较两个双打 预期结果和实际结果 但我不知道该怎么做 目前我的测试如下 Test public void te
  • 过滤两次 Lambda Java

    我有一个清单如下 1 2 3 4 5 6 7 和 预期结果必须是 1 2 3 4 5 6 7 我知道怎么做才能到7点 我的结果 1 2 3 4 5 6 我也想知道如何输入 7 我添加了i gt i objList size 1到我的过滤器
  • 在接口中使用默认方法是否违反接口隔离原则?

    我正在学习 SOLID 原则 ISP 指出 客户端不应被迫依赖于他们所使用的接口 不使用 在接口中使用默认方法是否违反了这个原则 我见过类似的问题 但我在这里发布了一个示例 以便更清楚地了解我的示例是否违反了 ISP 假设我有这个例子 pu
  • Java 集合的并集或交集

    建立并集或交集的最简单方法是什么Set在 Java 中 我见过这个简单问题的一些奇怪的解决方案 例如手动迭代这两个集合 最简单的单行解决方案是这样的 set1 addAll set2 Union set1 retainAll set2 In
  • 将流转换为 IntStream

    我有一种感觉 我在这里错过了一些东西 我发现自己做了以下事情 private static int getHighestValue Map
  • jdbc mysql loginTimeout 不起作用

    有人可以解释一下为什么下面的程序在 3 秒后超时 因为我将其设置为在 3 秒后超时 12秒 我特意关闭了mysql服务器来测试mysql服务器无法访问的这种场景 import java sql Connection import java
  • Hibernate 的 PersistentSet 不使用 hashCode/equals 的自定义实现

    所以我有一本实体书 public class Book private String id private String name private String description private Image coverImage pr
  • tomcat 中受密码保护的应用程序

    我正在使用 JSP Servlet 开发一个Web应用程序 并且我使用了Tomcat 7 0 33 as a web container 所以我的要求是tomcat中的每个应用程序都会password像受保护的manager applica
  • 为什么 Java 8 不允许非公共默认方法?

    让我们举个例子 public interface Testerface default public String example return Hello public class Tester implements Testerface
  • 专门针对 JSP 的测试驱动开发

    在理解 TDD 到底是什么之前 我就已经开始编写测试驱动的代码了 在没有实现的情况下调用函数和类可以帮助我以更快 更有效的方式理解和构建我的应用程序 所以我非常习惯编写代码 gt 编译它 gt 看到它失败 gt 通过构建其实现来修复它的过程
  • Python - 如何确定解析的 XML 元素的层次结构级别?

    我正在尝试使用 Python 解析 XML 文件中具有特定标记的元素并生成输出 excel 文档 该文档将包含元素并保留其层次结构 我的问题是我无法弄清楚每个元素 解析器在其上迭代 的嵌套深度 XML 示例摘录 3 个元素 它们可以任意嵌套
  • Eclipse 启动时崩溃;退出代码=13

    I am trying to work with Eclipse Helios on my x64 machine Im pretty sure now that this problem could occur with any ecli
  • 我如何在java中读取二进制数据文件

    因此 我正在为学校做一个项目 我需要读取二进制数据文件并使用它来生成角色的统计数据 例如力量和智慧 它的设置是让前 8 位组成一个统计数据 我想知道执行此操作的实际语法是什么 是不是就像读文本文件一样 这样 File file new Fi
  • 干净构建 Java 命令行

    我正在使用命令行编译使用 eclipse 编写的项目 如下所示 javac file java 然后运行 java file args here 我将如何运行干净的构建或编译 每当我重新编译时 除非删除所有内容 否则更改不会受到影响 cla
  • 在java中为组合框分配键

    我想添加一个JComboBox在 Swing 中这很简单 但我想为组合中的每个项目分配值 我有以下代码 JComboBox jc1 new JComboBox jc1 addItem a jc1 addItem b jc1 addItem
  • CamcorderProfile.videoCodec 返回错误值

    根据docs https developer android com reference android media CamcorderProfile html 您可以使用CamcorderProfile获取设备默认视频编解码格式 然后将其
  • 使用 svn 1.8.x、subclise 1.10 的 m2e-subclipse 连接器在哪里?

    我读到 m2e 的生产商已经停止生产 svn 1 7 以外的任何版本的 m2e 连接器 Tigris 显然已经填补了维护 m2e subclipse 连接器的空缺 Q1 我的问题是 使用 svn 1 8 x 的 eclipse 更新 url
  • Spring Boot 无法更新 azure cosmos db(MongoDb) 上的分片集合

    我的数据库中存在一个集合 documentDev 其分片键为 dNumber 样本文件 id 12831221wadaee23 dNumber 115 processed false 如果我尝试使用以下命令通过任何查询工具更新此文档 db
  • Java中super关键字的范围和使用

    为什么无法使用 super 关键字访问父类变量 使用以下代码 输出为 feline cougar c c class Feline public String type f public Feline System out print fe

随机推荐

  • 在 JavaScript 中嵌套“switch”案例:有速度优势吗?

    这里有新手问题 我有一个包含大量字符串的 开关 像这样按字母顺序拆分是否有速度优势 switch myString substring 0 1 case a switch myString case a string beginning w
  • 我应该如何在使用实例属性和类属性之间进行选择?

    我尝试了这个示例代码 class testclass classvar its classvariable LITERAL def init self x y self z x self classvar its initvariable
  • 如何在 Flutter 中为 Button 添加渐变?

    有没有办法改变ElevatedButton背景颜色渐变 如果没有一些小瑕疵或问题 例如缺少涟漪效应 不需要的边框 不尊重主题的内容 上述所有解决方案都无法真正发挥作用minWidth对于按钮 The 下面的解决方案没有上述问题 关键部分是使
  • 关于指针对齐的问题

    我正在研究内存池实现 我对指针对齐有点困惑 假设我有一个分配固定大小内存块的内存池 在创建内存池时我使用 malloc size num of block 如果分配的是对象 并且大小来自 sizeof 运算符对齐 则不必担心 但如果大小不均
  • 如何使用python检查任务管理器中某个进程是否正在运行

    我在 python 中有一个函数 当任务管理器中出现某个进程 例如 proc exe 时 该函数应该开始运行 如何使用 python 监控任务管理器中运行的进程 这是我改编的东西微软 http www microsoft com techn
  • 通过 cocoa pods 创建的 .xcworkspace 中的 .xcodeproj 文件被禁用

    我浏览互联网没有找到答案 所以这就是问题所在 我有一个项目 我在其中使用了 cocoa pods 因此通过 cocoa pods 为我创建的工作区文件打开它 但是在将我的操作系统 全新安装 更新到 MacOS Sierra 后 当我在 xc
  • Haskell Cabal 包 - 找不到 Paths_ 模块

    我正在开发一个 Haskell 项目 Happstack 服务器 Blaze HTML 前端作为主要库 我想添加一个静态数据目录 看起来你可以使用 Cabal 使用自动生成的Path
  • 在 django Rest 框架中实现角色

    我正在构建一个 API 应该拥有以下类型的用户 super user 创建 管理管理员 admin 管理事件 模型 和事件参与者 participants 参加活动 受管理员邀请参加活动 另外我想让每种类型的用户都有电话号码字段 I tri
  • 有没有办法设置一个变量一次并在多个地方使用它而不给它模块级别的范围?

    我有一个循环将用户窗体控件添加到集合中 由于多个地方都需要该集合 因此我将其放入模块中并在需要时调用它 这意味着该集合仅在需要时才位于内存中 但这也意味着我每次想要使用它时都会运行一个循环 I could已给出集合模块级别范围并在第一次需要
  • 类型“Promise”上不存在属性“finally”

    我试图对承诺使用finally 方法 但我不断收到此错误 Property finally does not exist on type Promise
  • 向 TextField 添加提示

    我想添加一个TextField带有集成的提示文本 用户提示 占位符 直到用户输入文本 当 TextField 获得焦点时 提示文本会消失 如果 TextField 失去焦点且未输入任何文本 则提示文本会重新出现 我最初认为这将是 Vaadi
  • Inno Setup:允许用户只选择可以安装软件的驱动器?

    我可以允许用户只选择要安装软件的驱动器吗 例如 他们可以选择C or D drive C Software D Software 但用户不能指定任何其他内容 就像他们不能选择安装下面的软件一样Downloads or MyDocumnets
  • 如何停止 CTE 中的递归?

    我有一个数据库表 如下所示 ID PredecessorID Data 43b1e103 d8c6 40f9 b031 e5d9ef18a739 null 55f6951b 5ed3 46c8 9ad5 64e496cb521a 43b1e
  • 为什么 hibernate 在 SAVE 之前执行 SELECT?

    为什么 hibernate 在保存对象之前要进行选择 我在互联网上找不到有用的信息 这是每次保存之前的正常行为吗 我发现这个话题 选择 hibernateTemplate save 的查询运行 https stackoverflow com
  • 如何在没有 SyncAdapter 的 Android 上实现帐户

    我正在利用内置帐户系统 使用 AccountManager API 为 Android 应用程序实现一个登录系统 在 Android 2 2 上一切都很好 但在 Android 2 1 上不包含 SyncAdapter 会导致帐户设置屏幕中
  • 新的 Windows 应用程序 - 什么语言?

    我们目前正处于开发 Windows 桌面应用程序的前期阶段 但当听到有关 Windows 8 Silverlight WPF Jupiter 的所有最新讨论时 我不知道该相信什么了 现在用WPF启动一个新项目是不是有问题 我应该切换到 Si
  • 检查多个位置的值并仅在源唯一时返回匹配项

    假设我有一个清单Vendors 阿斯达 乐购 Spar 我有一个清单Sources 或者这个类比中的供应商 家乐氏 Kellogg 吉百利 Cadbury 雀巢 Nestle 强生 Johnsons 帮宝适 Pampers Simple 等
  • Git推送更新远程服务器信息失败

    当我尝试将新分支推送到远程源时 出现以下错误 我能够在现有分支上推送提交 并且现有分支上没有问题 git push u origin master1 Fetching remote heads refs refs tags refs hea
  • Ajax 将文件上传到内容类型为 Multipart 的 GoLang 服务器

    我正在尝试使用多部分表单将音频文件上传到 Golang 服务器 然而 Go 返回错误 multipart NextPart bufio buffer full 我相信这表明我的 Javascript 请求中存在不属于多部分格式的内容 这是我
  • Java 中的递归下降解析器

    我想在序言中说这是我三年级编程语言课的家庭作业 我正在寻求一些帮助 我的作业如下 截止日期 2013年2月22日晚上11点55分提交 请将以下内容上传到CMS 1 源代码2 程序执行的屏幕截图 包括您使用的输入文件 使用您喜欢的任何编程语言