Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/grammar/consts.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

pub const EPSILON: char = 'ε';
pub const STRING_END: char = '$';

// NOTE: this could be in conflict with the Terminal symbols, so
// it is MANDATORY that the Terminal doesn´t have dots in it!
pub const ITEM_SEP: char = '.';
88 changes: 31 additions & 57 deletions src/grammar/grammar.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use std::collections::{BTreeSet, BTreeMap};

use crate::automata::DFA;
use crate::grammar::consts::{EPSILON, STRING_END};

use super::item::Item;

pub type NonTerminal = usize;
pub type Terminal = char;
Expand All @@ -11,10 +14,10 @@ pub enum Letter {
Terminal(Terminal),
}

#[derive(Debug, PartialEq)]
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord)]
pub struct Production {
lhs: NonTerminal,
rhs: Vec<Letter>,
pub lhs: NonTerminal,
pub rhs: Vec<Letter>,
}

#[derive(Debug, PartialEq)]
Expand All @@ -28,14 +31,24 @@ pub struct Grammar {
nullable: Option<BTreeSet<NonTerminal>>,
Comment thread
giospada marked this conversation as resolved.
}

const EPSILON: char = 'ε';
const STRING_END: char = '$';

// NOTE: this could be in conflict with the Terminal symbols, so
// it is MANDATORY that the Terminal doesn´t have dots in it!
const ITEM_SEP: char = '.';

impl Grammar {
pub fn new(start_symbol: NonTerminal, productions: Vec<Production>) -> Self {
Grammar {
start_symbol,
productions,
nullable: None,
}
}

pub fn get_start_symbol(&self) -> NonTerminal {
self.start_symbol
}

pub fn get_productions(&self) -> &Vec<Production> {
&self.productions
}

pub fn first(&mut self, letter: &Letter) -> BTreeSet<Terminal> {
if let None = self.nullable {
self.nullable = Some(self.get_nullable());
Expand Down Expand Up @@ -352,7 +365,7 @@ impl Grammar {
});

// add corresponding productions
let mut adj_list = self.transitions_to_adj_list();
let mut adj_list = self.productions_to_adj_list();
for unitary_couple in unitary_couples.iter() {
if unitary_couple.0 == unitary_couple.1 {
continue;
Expand Down Expand Up @@ -381,7 +394,7 @@ impl Grammar {
self.nullable = None;
}

fn transitions_to_adj_list(&self) -> BTreeMap<NonTerminal, BTreeSet<Vec<Letter>>> {
pub fn productions_to_adj_list(&self) -> BTreeMap<NonTerminal, BTreeSet<Vec<Letter>>> {
let mut adj_list: BTreeMap<NonTerminal, BTreeSet<Vec<Letter>>> = BTreeMap::new();
for production in self.productions.iter() {
adj_list.entry(production.lhs)
Expand All @@ -392,29 +405,14 @@ impl Grammar {
adj_list
}

pub fn get_itemization(&self) -> Vec<Production> {
let mut itemized_transitions = vec![];
for production in self.productions.iter() {
if production.rhs.len() == 1 && production.rhs[0] == Letter::Terminal(EPSILON) {
itemized_transitions.push(Production {
lhs: production.lhs,
rhs: vec![Letter::Terminal(ITEM_SEP)]
});
continue;
}

for i in 0..=production.rhs.len() {
let mut rhs = production.rhs.clone();

rhs.insert(i, Letter::Terminal(ITEM_SEP));
itemized_transitions.push(Production {
lhs: production.lhs,
rhs: rhs
});
}
}
pub fn add_fake_initial_state(&mut self) -> () {
let new_state = self.get_non_terminal().iter().max().unwrap() + 1;
self.productions.push(Production {
lhs: new_state,
rhs: vec![Letter::NonTerminal(self.start_symbol)]
});

itemized_transitions
self.start_symbol = new_state;
}
}

Expand Down Expand Up @@ -625,28 +623,4 @@ mod test {

assert_eq!(grammar, result);
}

#[test]
fn test_itemization() {
let grammar = get_test_grammar();

let items = grammar.get_itemization();

let result_productions = vec![
Production { lhs: 0, rhs: vec![Letter::Terminal(ITEM_SEP), Letter::NonTerminal(1), Letter::Terminal('b')] },
Production { lhs: 0, rhs: vec![Letter::NonTerminal(1), Letter::Terminal(ITEM_SEP), Letter::Terminal('b')] },
Production { lhs: 0, rhs: vec![Letter::NonTerminal(1), Letter::Terminal('b'), Letter::Terminal(ITEM_SEP)] },

Production { lhs: 0, rhs: vec![Letter::Terminal(ITEM_SEP), Letter::Terminal('c')] },
Production { lhs: 0, rhs: vec![Letter::Terminal('c'), Letter::Terminal(ITEM_SEP)] },

Production { lhs: 1, rhs: vec![Letter::Terminal(ITEM_SEP), Letter::Terminal('a'), Letter::NonTerminal(1)] },
Production { lhs: 1, rhs: vec![Letter::Terminal('a'), Letter::Terminal(ITEM_SEP), Letter::NonTerminal(1)] },
Production { lhs: 1, rhs: vec![Letter::Terminal('a'), Letter::NonTerminal(1), Letter::Terminal(ITEM_SEP)] },
Production { lhs: 1, rhs: vec![Letter::Terminal(ITEM_SEP)] },
];

assert!(items.iter().all(|item| result_productions.contains(item)));
assert!(result_productions.iter().all(|item| items.contains(item)));
}
}
Loading