Need help with grmtools?
Click the “chat” button below for chat support from the developer who created it, or find similar developers for support.

About the developer

188 Stars 10 Forks Other 1.4K Commits 3 Opened issues


Rust grammar tool libraries and binaries

Services available


Need anything else?

Contributors list

Grammar and parsing libraries for Rust

Bors enabled lrpar on lrlex on lrtable on cfgrammar on

grmtools is a suite of Rust libraries and binaries for parsing text, both at compile-time, and run-time. Most users will probably be interested in the compile-time Yacc feature, which allows traditional

files to be used (mostly) unchanged in Rust.


A minimal example using this library consists of two files (in addition to the grammar and lexing definitions). First we need to create a file
in the root of our project with the following content:
use cfgrammar::yacc::YaccKind;
use lrlex::CTLexerBuilder;

fn main() -> Result> { CTLexerBuilder::new() .lrpar_config(|ctp| { ctp.yacckind(YaccKind::Grmtools) .grammar_in_src_dir("calc.y") .unwrap() }) .lexer_in_src_dir("calc.l")? .build()?; Ok(()) }

This will generate and compile a parser and lexer, where the definitions for the lexer can be found in

[0-9]+ "INT"
\+ "+"
\* "*"
\( "("
\) ")"
[\t ]+ ;

and where the definitions for the parser can be found in

%start Expr
%avoid_insert "INT"
Expr -> Result:
      Expr '+' Term { Ok($1? + $3?) }
    | Term { $1 }

Term -> Result: Term '*' Factor { Ok($1? * $3?) } | Factor { $1 } ;

Factor -> Result: '(' Expr ')' { $2 } | 'INT' { let v = $1.map_err(|_| ())?; parse_int($lexer.span_str(v.span())) } ; %% // Any functions here are in scope for all the grammar actions above.

fn parse_int(s: &str) -> Result { match s.parse::() { Ok(val) => Ok(val), Err(_) => { eprintln!("{} cannot be represented as a u64", s); Err(()) } } }

We can then use the generated lexer and parser within our

file as follows:
use std::env;

use lrlex::lrlex_mod; use lrpar::lrpar_mod;

// Using lrlex_mod! brings the lexer for calc.l into scope. By default the // module name will be calc_l (i.e. the file name, minus any extensions, // with a suffix of _l). lrlex_mod!("calc.l"); // Using lrpar_mod! brings the parser for calc.y into scope. By default the // module name will be calc_y (i.e. the file name, minus any extensions, // with a suffix of _y). lrpar_mod!("calc.y");

fn main() { // Get the LexerDef for the calc language. let lexerdef = calc_l::lexerdef(); let args: Vec = env::args().collect(); // Now we create a lexer with the lexer method with which we can lex an // input. let lexer = lexerdef.lexer(&args[1]); // Pass the lexer to the parser and lex and parse the input. let (res, errs) = calc_y::parse(&lexer); for e in errs { println!("{}", e.pp(&lexer, &calc_y::token_epp)); } match res { Some(r) => println!("Result: {:?}", r), _ => eprintln!("Unable to evaluate expression.") } }

For more information on how to use this library please refer to the grmtools book, which also includes a more detailed quickstart guide.


lrpar contains several examples on how to use the

libraries, showing how to generate parse trees and ASTs, or execute code while parsing.


We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.