Crate gramatica [] [src]

This crate provides a binary to compile grammars into Rust code and a library implementing Earley's parsing algorithm to parse the grammars specified.

Usage

This crate is gramatica. To use it you should install it in order to acquire the gramatica_compiler binary and also add gramatica to your dependencies in your project's Cargo.toml.

[dependencies]
gramatica = "0.1"

Then, if you have made a grammar file example.rsg execute gramatica_compiler example.rsg > example.rs. Afterwards you may use the generated file example.rs as a source Rust file.

Example: calculator

The classical example is to implement a calculator.

extern crate gramatica;
use std::cmp::Ordering;
use std::io::BufRead;
use gramatica::{Associativity,EarleyKind,State,Parser,ParsingTablesTrait,AmbiguityInfo};

re_terminal!(Num(f64),"[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?");
re_terminal!(Plus,"\\+");
re_terminal!(Minus,"-");
re_terminal!(Star,"\\*");
re_terminal!(Slash,"/");
re_terminal!(Caret,"\\^");
re_terminal!(LPar,"\\(");
re_terminal!(RPar,"\\)");
re_terminal!(NewLine,"\\n");
re_terminal!(_,"\\s+");//Otherwise skip spaces

nonterminal Input(())
{
    () => (),
    (Input,Line) => (),
}

nonterminal Line(())
{
    (NewLine) => (),
    (Expression(value), NewLine) =>
    {
        println!("{}",value);
    },
}

nonterminal Expression(f64)
{
    (Num(value)) => value,
    #[priority(addition)]
    #[associativity(left)]
    (Expression(l),Plus,Expression(r)) => l+r,
    #[priority(addition)]
    #[associativity(left)]
    (Expression(l),Minus,Expression(r)) => l-r,
    #[priority(multiplication)]
    #[associativity(left)]
    (Expression(l),Star,Expression(r)) => l*r,
    #[priority(multiplication)]
    #[associativity(left)]
    (Expression(l),Slash,Expression(r)) => l/r,
    #[priority(addition)]
    #[associativity(left)]
    (Minus,Expression(value)) => -value,
    #[priority(exponentiation)]
    #[associativity(right)]
    (Expression(l),Caret,Expression(r)) => l.powf(r),
    (LPar,Expression(value),RPar) => value,
}

ordering!(exponentiation,multiplication,addition);

fn main()
{
    let stdin=std::io::stdin();
    for rline in stdin.lock().lines()
    {
        let line=rline.unwrap()+"\n";
        println!("line={}",line);
        match Parser::<Token,ParsingTables>::parse(&line,None)
        {
            Err(x) => println!("error parsing: {:?}",x),
            Ok(x) => println!("parsed correctly: {:?}",x),
        };
    }
}

Advanced Lexer

To define terminal tokens not expressable with regular expressions you may use the following.

terminal LitChar(char)
{
    fn _match(parser: &mut Parser<Token,ParsingTables>, source:&str) -> Option<(usize,char)>
    {
        let mut characters=source.chars();
        if (characters.next())==(Some('\''))
        {
            let mut c=characters.next().unwrap();
            let mut size=3;
            if c=='\\'
            {
                c=(characters.next().unwrap());
                size=4;
            }
            if characters.next().unwrap()=='\''
            {
                Some((size,c))
            }
            else
            {
                None
            }
        }
        else
        {
            None
        }
    }
}

Since version 0.1.0 there is also a keyword_terminal! macro:

keyword_terminal!(Const,"const");

Parsing values as match clauses

Each rule is written as a match clause, whose ending expression is the value that the nonterminal token gets after being parsed. For example:

nonterminal Stmts(Vec<StmtKind>)
{
    (Stmt(ref stmt)) => vec![stmt.clone()],
    (Stmts(ref stmts),Stmt(ref stmt)) =>
    {
        let mut new=(stmts.clone());
        new.push(stmt.clone());
        new
    },
}

Reductions only execute if they are part of the final syntactic tree.

Precedence by annotations

To avoid ambiguities you have two options: to ensure the grammar does not contain them or to priorize rules by introducing annotations. In the example of the calculator we have seen two kinds: - #[priority(p_name)] to declare a rule with priority p_name. Later there should be a ordering!(p_0,p_1,p_2,...) macro-like to indicate that p_0 should reduce before p_1. - #[associativity(left/right)] to decide how to proceed when nesting the same rule.

Structs

AmbiguityInfo
Parser
State
StateSet

Enums

Associativity
EarleyKind
ParsingError

Traits

ParsingTablesTrait