extern crate gramatica; use std::cmp::Ordering; use gramatica::{Associativity,EarleyKind,State,Parser,ParsingTablesTrait,AmbiguityInfo}; //See https://www.json.org/ use std::rc::Rc; //We define an auxiliar type to store JSON values #[derive(Clone,Debug,PartialEq)] enum JsonValue { Literal(String), Number(f64), Object(Vec<(String,JsonValue)>), Array(Vec), True, False, Null, } // ---- Start of the grammar ---- keyword_terminal!(True,"true"); keyword_terminal!(False,"false"); keyword_terminal!(Null,"null"); re_terminal!(Number(f64),"[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?"); terminal LitStr(String) { //This function has limited escaping capabilities fn _match(parser: &mut Parser, source:&str) -> Option<(usize,String)> { let mut ret=None; let mut characters=source.chars(); if (characters.next())!=(Some('"')) { } else { let mut size=1; let mut r=String::from("\""); while true { match characters.next() { None => break, Some('"') => { ret=(Some((size+1,r+&"\""))); break; }, Some('\\') => { match characters.next() { None => break, //Some(c) => r+='\\'+c, Some(c) => { r.push('\\'); r.push(c); } }; size+=2; }, Some(c) => { //r+=&String::from(c); r.push(c); size+=1; }, }; } } ret } } re_terminal!(LBrace,"\\{"); re_terminal!(RBrace,"\\}"); re_terminal!(LBracket,"\\["); re_terminal!(RBracket,"\\]"); re_terminal!(Comma,","); re_terminal!(Colon,":"); re_terminal!(_,"\\s+|\n");//Otherwise skip spaces nonterminal Object(JsonValue) { (LBrace,RBrace) => JsonValue::Object(vec![]), (LBrace,Members(ref list),RBrace) => JsonValue::Object(list.clone()), } nonterminal Members(Vec<(String,JsonValue)>) { (Pair(ref s,ref value)) => vec![(s.clone(),value.clone())], //(Pair,Comma,Members) => (), (Members(ref list),Comma,Pair(ref s,ref value)) => { let mut new=(list.clone()); new.push((s.clone(),value.clone())); new }, } nonterminal Pair(String,JsonValue) { (LitStr(ref s),Colon,Value(ref value)) => (s.clone(),value.clone()), } nonterminal Array(Vec) { (LBracket,RBracket) => vec![], (LBracket,Elements(ref list),RBracket) => list.clone(), } nonterminal Elements(Vec) { (Value(ref value)) => vec![value.clone()], //(Value,Comma,Elements) => (), (Elements(ref list),Comma,Value(ref value)) => { let mut new=(list.clone()); new.push(value.clone()); new }, } nonterminal Value(JsonValue) { (LitStr(ref s)) => JsonValue::Literal(s.clone()), (Number(v)) => JsonValue::Number(v), (Object(ref value)) => value.clone(), (Array(ref list)) => JsonValue::Array(list.clone()), (True) => JsonValue::True, (False) => JsonValue::False, (Null) => JsonValue::Null, } // ---- End of the grammar ---- use std::io::{BufRead,Read}; //As example, we parse stdin for a JSON object fn main() { let stdin=std::io::stdin(); let mut buf=String::new(); stdin.lock().read_to_string(&mut buf); match Parser::::parse(&buf,None) { Err(x) => println!("error parsing: {:?}",x), Ok(x) => println!("parsed correctly: {:?}",x), }; }