`
yangdong
  • 浏览: 66424 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

JParsec中如何在parser规则里引用lexer规则

    博客分类:
  • Java
 
阅读更多
Java 的 Parser combinator 中最有名应该是 JParsec 了。随着 Java 8 的发布,我们也可以用 lambda 表达式来写规则了。刚开始的时候我以为它跟 C# 下面的 Sprache 会比较像,API 应该很容易。结果我错了。Sprache 的思想跟《Monadic Parser Combinators》这篇论文里的提到的设计方法如出一辙,是不区分 lexer 和 parser 的。但是 JParsec 区分。如果在 parser 对应的规则里面使用 lexer 的规则,会导致异常。可以参看 ParserState 类:

@Override CharSequence characters() {
    throw new IllegalStateException(
        "Cannot scan characters on tokens.");
}


如果你在尝试用 JParsec 写规则时遇到了不知道怎么在 parser 规则中引用 lexer 规则的问题,恭喜你,看完下面的代码你会应该知道怎么做了。

整体示意图:



比如解析一段 key/value 文本:

"update": "2014-10-28"


为了解析双引号的部分写一个 lexer 规则:

private static final
Parser<Tokens.Fragment> STRING_LITERAL =
    Scanners.DOUBLE_QUOTE_STRING
            .map(patchTag(Tag.STRING))
            .label("string literal");

enum Tag {
    STRING
}

private static
Map<String, Tokens.Fragment> patchTag(Object tag) {
    return str -> new Tokens.Fragment(str, tag);
}


除 patchTag 函数和 Tag 枚举之外其它的都是 JParsec 的 API。patchTag 的作用就让 lexer 在运行的时候将 STRING_LITERAL 规则所解析出来的字符串打上 STRING 这个 tag。这样在后面的 parser 规则部分用这个 tag 将字符串规则取出来:

private final
Parser<String> stringLiteral =
    Parsers.token(withTag(Tag.STRING))
           // 除掉引号
           .map(s -> s.substring(1, s.length() - 1))
           .label("string literal");

private static TokenMap<String>
withTag(Object tag) {
    return token -> {
        Object value = token.value();
        if (value instanceof Tokens.Fragment) {
            Tokens.Fragment fragment =
                (Tokens.Fragment) value;
            if (tag.equals(fragment.tag())) {
                return fragment.text();
            }
        }
        return null;
    };
}


这样就可以做一个规则来匹配 "update": "2014-10-28" 这样的文本了:

private Parser<StatAstKeyValue> keyValue =
    Parsers.sequence(
        stringLiteral,
        OPERATORS.token(":"),
        stringLiteral,
        (k, ignored, v) ->
            new StatAstKeyValue(k, v))
    .label("keyValue");

private static final
Terminals OPERATORS =
    Terminals.operators("{", "}", ",", ":");


文本中的空格部分要求在 lexer 中额外定义一个空白字符的规则:

private static final
Parser<Void> WHITESPACES = Scanners.WHITESPACES;


为了达到忽略空白字符的目的,我们可以用 Parser#skipMany() 这样的 combinator,也可以用 JParsec 的官方教程上的做法:

private Parser<List<Token>>
TERMINALS = TOKENIZER.lexer(
    WHITESPACES.or(Parsers.always())
);


这里将 WHITESPACES.or(Parsers.always()) 作为分隔符来分隔 TOKENIZER 解析出来的 token。如果不加 Parsers.always(),会导致可以解析

"k" : "v"


但不能解析

"k": "v"


注意第 2 个例子中冒号的前面没有空格。
  • 大小: 25.5 KB
分享到:
评论

相关推荐

    从零开始用 Go 实现 Lexer & Parser

    总结来说,文件内容涉及了使用Go语言从零开始实现Lexer和Parser的基础知识,并提到了在软件开发过程中如何面对快速迭代、内容管理、版本控制和自动化部署等实际问题。这些都是软件工程师在日常工作中可能遇到的典型...

    Rust VBScript lexer and parser

    标题中的"Rust VBScript lexer and parser"指的是一项使用Rust语言实现的VBScript的词法分析器和解析器。词法分析器(lexer),也称为扫描器,负责将源代码文本转换为一系列有意义的标记(tokens)。这些标记代表了...

    lexer and parser using jflex and cup

    编译器的设计与实现涉及多个阶段,其中“词法分析”(lexer)和“语法分析”(parser)是两个至关重要的步骤。这里我们将深入探讨利用JFlex和CUP这两个工具来完成这些任务。 **词法分析(Lexer)** 词法分析,也...

    Lexer-master_编译器_词法分析器_lexer_

    在 "Lexer-master" 中,你可以找到实现这一功能的源代码。它可能包含以下组件: 1. **词法规则定义**:这是Lexer的核心部分,定义了各种词法规则,每个规则对应一种词法单元。例如,定义一个规则匹配所有的数字字符...

    2021-1-26 Pool_Lexer_Parser.zip

    在这个项目中,Parser.cpp 文件可能是实现解析逻辑的地方,它可能使用了LR、LL或递归下降等解析策略。把AST构造放到Parser内部使得一次扫描就能完成所有标记的处理,提高了效率。 Utils.cpp 和 Utils.h 可能包含了...

    在VS2013下配置Parser Generator1

    在解决方案属性中,需要配置VC++目录里的设置。包含目录、引用目录和库目录等。 * 包含目录:将*\Parser Generator 2\Cpp\Include添加到包含目录中。 * 引用目录:将*\Parser Generator 2\Cpp\Lib\mvsc32添加到引用...

    enju parser enju parser

    enju parser enju parser

    sql-parser-master.zip_Parser_SQL parser

    在"sql-parser-master.zip"这个压缩包中,我们很可能是得到了一个名为"Parser_SQL parser"的项目源码,它是一个SQL解析器的模拟实现。这个解析器可能用于分析、验证和转化SQL查询,以便于执行。 SQL解析器的工作...

    javaParser 包 javaparser-core-3.6.16.jar

    要使用 JavaParser,你需要在项目中引入 `javaparser-core-3.6.16.jar`,然后可以创建 `JavaParser` 实例来解析 Java 文件。例如,以下代码演示了如何读取并打印一个 Java 类的 AST: ```java import ...

    Stanford_Parser中文句法分析器使用教程

    在 Eclipse 中,可以在“运行”-“运行配置”-“自变量”-“vm 参数”中添加“--Xmx1024m”以设置最大内存大小为 1024MB。其次,需要确保 Tokenize 选项被选中,并且文件格式为 utf-8,以便正确地分词。 二、命令行...

    DOMParser解析xml

    在IT行业中,XML(eXtensible Markup Language)是一种用于存储和传输数据的标准化格式,尤其在Web应用程序和数据交换中广泛应用。DOMParser是JavaScript中处理XML文档的主要工具,它允许我们将XML数据转换为DOM...

    sql-lexer-parser

    在这个项目中,`sql-lexer-parser`专注于SELECT语句的解析,这包括词法分析(lexer)和语法分析(parser)两个步骤。 2. **词法分析(Lexer)**: 词法分析是将输入的SQL字符串分解成一系列有意义的符号(tokens)...

    Parser_Generator.rar

    Parser_Generator是一个在Windows操作系统环境下使用的工具,主要用于生成解析器(Parser)和生成器(Generator)。解析器是计算机科学中的一个重要组件,它处理输入源代码,将其转化为抽象语法树(AST),这是理解...

    Node.js-规则判断引擎结合`service-rule-parser`使用

    本篇文章将深入探讨如何在Node.js项目中结合`service-rule-parser`来构建规则判断引擎。 首先,`service-rule-parser`的核心功能是对JSON格式的规则进行解析和执行。这种规则通常包含了一系列条件(如变量比较、...

    python lexer yacc 手册

    - **运行时调试**:在执行过程中查看lexer和parser的状态。 **优化模式**:提高lexer和parser的性能。 #### 5. 多个语法和词法分析器 - **多个 lexer 和 parser**:同时处理多种语言或文法。 #### 6. 使用 ...

    javaparser教程

    在使用JavaParser时,经常需要解决代码中的符号和引用。教程中可能会讲到如何设置Java符号求解器,如何获取引用的类型,解决绝对名称的类型,以及在上下文中解决类型和方法调用。 9. 使用组合类型求解器和内存类型...

    C# lexer 语法解析器

    These tools comprise a lexer generator and a LALR(1) parser generator, written entirely in C# and generating C#.

    Antlr入门详细教程

    - Token类型文件(如`PTokenTypes.java`)包含了Lexer中定义的Token类型,供Parser引用。 5. **执行流程** - 编写一个主程序(如`Main`类),创建Lexer和Parser对象,然后调用Parser的起始规则方法进行解析。 - ...

    parser中文API以及示例.pdf

    Parser中文API以及示例 Parser中文API是用于解析HTML网页的Java库,提供了一个强大且灵活的HTML解析引擎。下面是Parser中文API的详细介绍: Parser类 Parser类是Parser中文API的核心类,提供了多种构造函数用于...

    c# sqlparser

    C# SQLParser是一个用于解析和操作SQL语句的库,主要功能是帮助开发者在C#环境中分析SQL查询,特别是为了动态地添加`WHERE`和`ORDER BY`子句。这个库对于那些需要处理用户输入的SQL片段或者需要自定义SQL构建逻辑的...

Global site tag (gtag.js) - Google Analytics