7 个稳定版本

7.0.0 2023年6月20日
6.1.1 2023年6月20日
5.0.0 2023年6月14日
4.0.0 2023年6月14日
1.0.0 2023年6月12日

#40解析工具


kiki 使用

MIT 许可证

285KB
10K SLoC

吉基

crates.io

吉基是一个为 Rust 设计的极简解析生成器。

目录

如何使用吉基?

阅读 快速入门指南

为什么使用吉基?

  • 易于学习。 如果你之前使用过其他解析生成器(例如,Bison/yacc),你可以在 10分钟内学会吉基
  • 易于编写。 如 Bison 或 lalrpop 之类的工具强制你编写语法、语义动作和语法树类型定义。吉基让你只需编写类型定义。吉基从类型定义中推断语法和语义动作。
  • 易于阅读。 吉基具有极简的语法。这使得它易于学习,也易于阅读。

吉基的限制

  • 吉基仅支持 LALR(1) 语法。
  • 吉基解析标记序列,而不是字符串。
    • 换句话说,你必须提供自己的词法分析器。你可以手动实现词法分析器,或者使用词法分析器生成器(例如,logos)。

示例

在本节中,我们将构建一个玩具解析器,它可以识别算术表达式。例如

  • 42
  • 42 + 53
  • 29 + (893 * 7)

为了简单起见,这种语言没有运算符优先级。相反,你必须使用括号(例如,29 + (893 * 7))。

让我们比较一下我们如何使用 Bison 和吉基构建解析器。

使用 Bison

假设 Bison 假设支持 Rust(而不是仅支持 C/C++)。那么你可能写成

%{
    enum Expr {
        Num(i32),
        Op {
            left: Box<Expr>,
            kind: OpKind,
            right: Box<Expr>,
        },
    }

    enum OpKind {
        Add,
        Sub,
        Cons,
        Div,
    }
}

%token <i32> NUM

// Other than NUM, the rest of the tokens
// only have one possible value each.
// So, we set their type to the unit type (`()`).
%token <()> PLUS
%token <()> MINUS
%token <()> STAR
%token <()> SLASH
%token <()> LPAREN
%token <()> RPAREN

%start expr

%%

expr
    : term
        {
            $$ = $1;
        }
    | term PLUS term
        {
            $$ = Expr::Op {
                left: Box::new($1),
                kind: OpKind::Add,
                right: Box::new($3),
            };
        }
    | term MINUS term
        {
            $$ = Expr::Op {
                left: Box::new($1),
                kind: OpKind::Sub,
                right: Box::new($3),
            };
        }
    | term STAR term
        {
            $$ = Expr::Op {
                left: Box::new($1),
                kind: OpKind::Cons,
                right: Box::new($3),
            };
        }
    | term SLASH term
        {
            $$ = Expr::Op {
                left: Box::new($1),
                kind: OpKind::Div,
                right: Box::new($3),
            };
        }
;

term
    : NUM
        {
            $$ = Expr::Num($1);
        }
    | LPAREN expr RPAREN
        {
            $$ = $2;
        }
;

请注意,你必须编写 件事情

  1. 语法(即 expr : term ...;term : NUM ...;)。
  2. 语义动作(例如,$$ = Expr::Op {...};)。
  3. 语法树类型定义(即,enum Expr {...}enum OpKind {...})。

使用Kiki

在Kiki中,你只需

terminal Token {
    $Num: i32
    $Plus: ()
    $Minus: ()
    $Star: ()
    $Slash: ()
    $LParen: ()
    $RParen: ()
}

start Expr

enum Expr {
    Term(Term)
    Op {
        left: Expr
        kind: OpKind
        right: Expr
    }
}

enum OpKind {
    Add(_: $Plus)
    Sub(_: $Minus)
    Cons(_: $Star)
    Div(_: $Div)
}

enum Term {
    Num($Num)
    Parenthesized(
        _: $LParen
        Expr
        _: $RParen
    )
}

观察这段代码更为简洁和简短。无需编写语法、语义动作和语法树类型定义,只需编写语法树类型定义。Kiki可以从类型定义中推断语法和语义动作。

指南

您可以在此处阅读用户指南:这里。指南详细解释了Kiki。这不是一篇快速阅读的文章。

如果您希望尽快理解Kiki,请点击这里

贡献

欢迎贡献。只需打开新问题或拉取请求,我会查看。所有形式的贡献(例如,错误修复、测试、文档、错别字纠正)都很有帮助。

依赖关系

~0.8–2.1MB
~36K SLoC