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

softdevteam
188 Stars 10 Forks Other 1.4K Commits 3 Opened issues

Description

Rust grammar tool libraries and binaries

Services available

!
?

Need anything else?

Contributors list

Grammar and parsing libraries for Rust

Bors enabled lrpar on crates.io lrlex on crates.io lrtable on crates.io cfgrammar on crates.io

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

.y
files to be used (mostly) unchanged in Rust.

Quickstart

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

build.rs
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

src/calc.l
:
%%
[0-9]+ "INT"
\+ "+"
\* "*"
\( "("
\) ")"
[\t ]+ ;

and where the definitions for the parser can be found in

src/calc.y
:
%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

src/main.rs
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.

Examples

lrpar contains several examples on how to use the

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

Documentation

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.