mirror of
https://github.com/ParkerTenBroeck/automata.git
synced 2026-06-07 05:28:45 -04:00
NPDA's working
This commit is contained in:
parent
f375757fd6
commit
0e285ec100
6 changed files with 356 additions and 167 deletions
15
example.npda
15
example.npda
|
|
@ -2,18 +2,21 @@
|
||||||
Q = {q0, q1} // states
|
Q = {q0, q1} // states
|
||||||
E = {a, b} // alphabet
|
E = {a, b} // alphabet
|
||||||
T = {z0, A, B} // stack
|
T = {z0, A, B} // stack
|
||||||
I = q0
|
q0 = q0
|
||||||
|
z0 = z0
|
||||||
|
|
||||||
// construct all possible permutations of A's and B's
|
// construct all possible permutations of A's and B's
|
||||||
d(q0, epsilon, z0) = { (q0, [A z0]), (q0, [B z0]) }
|
d(q0, epsilon, z0) = { (q0, [A z0]), (q0, [B z0]) }
|
||||||
d(q0, epsilon, A) = { (q0, [A A]), (q0, [B A]) }
|
d(q0, epsilon, A) = { (q0, [A A]), (q0, [B A]) }
|
||||||
|
|
||||||
d(q0, epsilon, B) = { (q0, [A B]), (q0, [B B]) }
|
d(q0, epsilon, B) = { (q0, [A B]), (q0, [B B]) }
|
||||||
|
|
||||||
// transition to q1
|
// transition to q1
|
||||||
d(q0, epsilon, z0)={ (q1, z0) }
|
d(q0, epsilon, z0) = { (q1, z0) }
|
||||||
d(q0, epsilon, A)={ (q1, A) }
|
d(q0, epsilon, A) = { (q1, A) }
|
||||||
d(q0, epsilon, B)={ (q1, B) }
|
|
||||||
|
//d(q0, epsilon, B) = { (q1, B) }
|
||||||
|
|
||||||
// consume stack until empty
|
// consume stack until empty
|
||||||
d(q1, a, A)={(q1, epsilon)}
|
d(q1, a, A) = { (q1, epsilon) }
|
||||||
d(q1, b, B)={(q1, epsilon)}
|
d(q1, b, B) = { (q1, epsilon) }
|
||||||
|
|
|
||||||
|
|
@ -7,38 +7,76 @@ pub mod npda;
|
||||||
pub mod ntm;
|
pub mod ntm;
|
||||||
pub mod tm;
|
pub mod tm;
|
||||||
|
|
||||||
|
pub trait Get<Idx>{
|
||||||
|
type Output;
|
||||||
|
fn get(&self, idx: Idx) -> Option<&Self::Output>;
|
||||||
|
fn get_mut(&mut self, idx: Idx) -> Option<&mut Self::Output>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait GetDefault<Idx>{
|
||||||
|
type Output: Default;
|
||||||
|
fn get_or_insert_default(&mut self, idx: Idx) -> &Self::Output;
|
||||||
|
fn get_mut_or_insert_default(&mut self, idx: Idx) -> &mut Self::Output;
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! index {
|
||||||
|
($ty: ident, $self:ident, $collection: expr, $index_calc: expr, $index: pat = $index_ty: ty $(, $default: expr)?) => {
|
||||||
|
impl<T> Get<$index_ty> for $ty<T> {
|
||||||
|
type Output = T;
|
||||||
|
fn get(&$self, $index: $index_ty) -> Option<&T>{
|
||||||
|
$collection.get($index_calc)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_mut(&mut $self, $index: $index_ty) -> Option<&mut T>{
|
||||||
|
$collection.get_mut($index_calc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> std::ops::Index<$index_ty> for $ty<T>{
|
||||||
|
type Output = T;
|
||||||
|
|
||||||
|
fn index(& $self, $index: $index_ty) -> &T{
|
||||||
|
$collection.get($index_calc).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> std::ops::IndexMut<$index_ty> for $ty<T>{
|
||||||
|
fn index_mut(&mut $self, $index: $index_ty) -> &mut T{
|
||||||
|
$collection.get_mut($index_calc).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$(
|
||||||
|
impl<T: Default> GetDefault<$index_ty> for $ty<T> {
|
||||||
|
type Output = T;
|
||||||
|
fn get_or_insert_default(&mut $self, $index: $index_ty) -> &T{
|
||||||
|
$default
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_mut_or_insert_default(&mut $self, $index: $index_ty) -> &mut T{
|
||||||
|
$default
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)?
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Copy, Hash, PartialEq, Eq)]
|
#[derive(Clone, Debug, Copy, Hash, PartialEq, Eq)]
|
||||||
pub struct State(u16);
|
pub struct State(u16);
|
||||||
|
|
||||||
#[derive(Clone, Debug, Copy, Hash, PartialEq, Eq)]
|
#[derive(Clone, Debug, Copy, Hash, PartialEq, Eq)]
|
||||||
pub struct Symbol(u16);
|
pub struct Symbol(u16);
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct StateMap<T>(Vec<T>);
|
pub struct StateMap<T>(Vec<T>);
|
||||||
|
|
||||||
trait Get<Idx> {
|
index!(StateMap, self, self.0, index.0 as usize, index = State);
|
||||||
type Output;
|
|
||||||
fn get(&self, index: Idx) -> Option<&Self::Output>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Get<State> for StateMap<T> {
|
|
||||||
type Output = T;
|
|
||||||
|
|
||||||
fn get(&self, index: State) -> Option<&Self::Output> {
|
|
||||||
self.0.get(index.0 as usize)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct SymbolMap<T>(Vec<T>);
|
pub struct SymbolMap<T>(Vec<T>);
|
||||||
|
|
||||||
impl<T> Get<Symbol> for SymbolMap<T> {
|
index!(SymbolMap, self, self.0, index.0 as usize, index = Symbol);
|
||||||
type Output = T;
|
|
||||||
|
|
||||||
fn get(&self, index: Symbol) -> Option<&Self::Output> {
|
|
||||||
self.0.get(index.0 as usize)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct StateSymbolMap<T> {
|
pub struct StateSymbolMap<T> {
|
||||||
|
|
@ -46,40 +84,18 @@ pub struct StateSymbolMap<T> {
|
||||||
max_state: u16,
|
max_state: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Get<(State, Symbol)> for StateSymbolMap<T> {
|
|
||||||
type Output = T;
|
|
||||||
|
|
||||||
fn get(&self, (state, symbol): (State, Symbol)) -> Option<&Self::Output> {
|
index!(StateSymbolMap, self, self.map, state.0 as usize + self.max_state as usize * symbol.0 as usize, (state, symbol) = (State, Symbol));
|
||||||
self.map
|
index!(StateSymbolMap, self, self.map, state.0 as usize + self.max_state as usize * symbol.0 as usize, (symbol, state) = (Symbol, State));
|
||||||
.get(state.0 as usize + self.max_state as usize * symbol.0 as usize)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct CharMap<T>(HashMap<char, T>);
|
pub struct CharMap<T>(HashMap<char, T>);
|
||||||
impl<T> Get<char> for CharMap<T> {
|
|
||||||
type Output = T;
|
|
||||||
|
|
||||||
fn get(&self, index: char) -> Option<&Self::Output> {
|
index!(CharMap, self, self.0, &char, char = char, self.0.entry(char).or_default());
|
||||||
self.0.get(&index)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct CharEpsilonMap<T>(HashMap<Option<char>, T>);
|
pub struct CharEpsilonMap<T>(HashMap<Option<char>, T>);
|
||||||
|
|
||||||
impl<T> Get<char> for CharEpsilonMap<T> {
|
index!(CharEpsilonMap, self, self.0, &Some(char), char = char, self.0.entry(Some(char)).or_default());
|
||||||
type Output = T;
|
index!(CharEpsilonMap, self, self.0, &char, char = Option<char>, self.0.entry(char).or_default());
|
||||||
|
|
||||||
fn get(&self, index: char) -> Option<&Self::Output> {
|
|
||||||
self.0.get(&Some(index))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Get<Option<char>> for CharEpsilonMap<T> {
|
|
||||||
type Output = T;
|
|
||||||
|
|
||||||
fn get(&self, index: Option<char>) -> Option<&Self::Output> {
|
|
||||||
self.0.get(&index)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -7,14 +7,13 @@ struct To(State, Vec<Symbol>);
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct TransitionTable {
|
pub struct TransitionTable {
|
||||||
pub(in super::npda) initial_state: State,
|
initial_state: State,
|
||||||
initial_stack: Symbol,
|
initial_stack: Symbol,
|
||||||
state_names: Vec<String>,
|
state_names: StateMap<String>,
|
||||||
symbol_names: Vec<String>,
|
symbol_names: SymbolMap<String>,
|
||||||
alphabet: HashSet<char>,
|
alphabet: HashSet<char>,
|
||||||
|
|
||||||
accept_empty: bool,
|
final_states: Option<StateMap<bool>>,
|
||||||
final_states: Vec<bool>,
|
|
||||||
transitions: StateSymbolMap<CharEpsilonMap<Vec<To>>>,
|
transitions: StateSymbolMap<CharEpsilonMap<Vec<To>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -31,8 +30,15 @@ pub struct Simulator {
|
||||||
running: Vec<NPDA>,
|
running: Vec<NPDA>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum SimulatorResult{
|
||||||
|
Pending,
|
||||||
|
Reject,
|
||||||
|
Accept(NPDA)
|
||||||
|
}
|
||||||
|
|
||||||
impl Simulator {
|
impl Simulator {
|
||||||
pub fn begin(input: impl Into<String>, table: TransitionTable) -> Self {
|
pub fn begin(input: impl Into<String>, table: TransitionTable) -> Self {
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
input: input.into(),
|
input: input.into(),
|
||||||
running: vec![NPDA {
|
running: vec![NPDA {
|
||||||
|
|
@ -44,7 +50,8 @@ impl Simulator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn step(&mut self) -> Option<NPDA> {
|
pub fn step(&mut self) -> SimulatorResult {
|
||||||
|
println!("step, ({}) paths", self.running.len());
|
||||||
let mut new = Vec::new();
|
let mut new = Vec::new();
|
||||||
for mut npda in self.running.drain(..) {
|
for mut npda in self.running.drain(..) {
|
||||||
let Some(top) = npda.stack.pop() else {
|
let Some(top) = npda.stack.pop() else {
|
||||||
|
|
@ -73,10 +80,12 @@ impl Simulator {
|
||||||
.get(npda.position..)
|
.get(npda.position..)
|
||||||
.and_then(|c| c.chars().next())
|
.and_then(|c| c.chars().next())
|
||||||
else {
|
else {
|
||||||
if self.table.final_states[npda.state.0 as usize]
|
if let Some(final_states) = &self.table.final_states
|
||||||
|| self.table.accept_empty && npda.stack == [self.table.initial_stack]
|
&& final_states.get(npda.state).copied().unwrap_or_default()
|
||||||
{
|
{
|
||||||
return Some(npda.clone());
|
return SimulatorResult::Accept(npda.clone());
|
||||||
|
} else if npda.stack == [self.table.initial_stack] {
|
||||||
|
return SimulatorResult::Accept(npda.clone());
|
||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -100,7 +109,11 @@ impl Simulator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.running = new;
|
self.running = new;
|
||||||
None
|
if self.running.is_empty(){
|
||||||
|
SimulatorResult::Reject
|
||||||
|
}else{
|
||||||
|
SimulatorResult::Pending
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -108,7 +121,7 @@ impl Simulator {
|
||||||
|
|
||||||
use crate::loader::{
|
use crate::loader::{
|
||||||
DELTA_LOWER, GAMMA_UPPER, SIGMA_UPPER, Spanned,
|
DELTA_LOWER, GAMMA_UPPER, SIGMA_UPPER, Spanned,
|
||||||
ast::{self, Symbol as Sym, Tuple},
|
ast::{self, Symbol as Sym},
|
||||||
lexer::Lexer,
|
lexer::Lexer,
|
||||||
log::Logs,
|
log::Logs,
|
||||||
parser::Parser,
|
parser::Parser,
|
||||||
|
|
@ -130,11 +143,12 @@ impl TransitionTable {
|
||||||
let mut initial_state = None;
|
let mut initial_state = None;
|
||||||
let mut initial_stack = None;
|
let mut initial_stack = None;
|
||||||
|
|
||||||
let mut states = HashSet::new();
|
let mut states = HashMap::new();
|
||||||
let mut stack_symbols = HashSet::new();
|
let mut stack_symbols = HashMap::new();
|
||||||
let mut alphabet = HashSet::new();
|
let mut alphabet = HashSet::new();
|
||||||
let mut final_states = None;
|
let mut final_states = None;
|
||||||
let mut accept_empty = false;
|
|
||||||
|
let mut transitions_map = HashMap::new();
|
||||||
|
|
||||||
for Spanned(element, span) in ast {
|
for Spanned(element, span) in ast {
|
||||||
use Spanned as S;
|
use Spanned as S;
|
||||||
|
|
@ -152,12 +166,19 @@ impl TransitionTable {
|
||||||
let Some(ident) = item.expect_ident(&mut logs) else {
|
let Some(ident) = item.expect_ident(&mut logs) else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
if !states.insert(ident) {
|
let state = match states.len().try_into() {
|
||||||
|
Ok(ok) => State(ok),
|
||||||
|
Err(_) => {
|
||||||
|
logs.emit_error("too many states defined", item.1);
|
||||||
|
State(0)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if states.insert(ident, state).is_some() {
|
||||||
logs.emit_error("state redefined", item.1);
|
logs.emit_error("state redefined", item.1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if list.is_empty(){
|
if list.is_empty() {
|
||||||
logs.emit_error("states cannot be empty", *span);
|
logs.emit_error("states cannot be empty", *span);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -177,15 +198,18 @@ impl TransitionTable {
|
||||||
logs.emit_error("letter cannot be longer than one char", item.1);
|
logs.emit_error("letter cannot be longer than one char", item.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if !alphabet.insert(ident) {
|
if !alphabet.insert(ident.chars().next().unwrap_or_default()) {
|
||||||
logs.emit_error("letter redefined", item.1);
|
logs.emit_error("letter redefined", item.1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if list.is_empty(){
|
if list.is_empty() {
|
||||||
logs.emit_error("alphabet cannot be empty", *span);
|
logs.emit_error("alphabet cannot be empty", *span);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TL::Assignment(S(Dest::Ident("F"), _), list) => {
|
TL::Assignment(S(Dest::Ident("F"), _), list) => {
|
||||||
|
if final_states.is_some() {
|
||||||
|
logs.emit_error("final states already set", *span);
|
||||||
|
}
|
||||||
let mut map = HashSet::new();
|
let mut map = HashSet::new();
|
||||||
let Some(list) = list.expect_set(&mut logs) else {
|
let Some(list) = list.expect_set(&mut logs) else {
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -194,16 +218,13 @@ impl TransitionTable {
|
||||||
let Some(ident) = item.expect_ident(&mut logs) else {
|
let Some(ident) = item.expect_ident(&mut logs) else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
if !states.contains(ident) {
|
if let Some(state) = states.get(ident){
|
||||||
|
if !map.insert(*state) {
|
||||||
|
logs.emit_error("final state redefined", item.1);
|
||||||
|
}
|
||||||
|
} else{
|
||||||
logs.emit_error("final state not defined in set of states", item.1);
|
logs.emit_error("final state not defined in set of states", item.1);
|
||||||
}
|
}
|
||||||
if !map.insert(ident) {
|
|
||||||
logs.emit_error("final states redefined", item.1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if final_states.is_some() {
|
|
||||||
logs.emit_error("final states already set", *span);
|
|
||||||
}
|
}
|
||||||
final_states = Some(map);
|
final_states = Some(map);
|
||||||
}
|
}
|
||||||
|
|
@ -218,40 +239,48 @@ impl TransitionTable {
|
||||||
let Some(ident) = item.expect_ident(&mut logs) else {
|
let Some(ident) = item.expect_ident(&mut logs) else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
if !stack_symbols.insert(ident) {
|
let symbol = match stack_symbols.len().try_into() {
|
||||||
|
Ok(ok) => Symbol(ok),
|
||||||
|
Err(_) => {
|
||||||
|
logs.emit_error("too many stack symbols defined", item.1);
|
||||||
|
Symbol(0)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if stack_symbols.insert(ident, symbol).is_some() {
|
||||||
logs.emit_error("stack symbol redefined", item.1);
|
logs.emit_error("stack symbol redefined", item.1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if list.is_empty(){
|
if list.is_empty() {
|
||||||
logs.emit_error("stack symbols cannot be empty", *span);
|
logs.emit_error("stack symbols cannot be empty", *span);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TL::Assignment(S(Dest::Ident("I" | "q0"), _), S(src, src_d)) => match src {
|
TL::Assignment(S(Dest::Ident("I" | "q0"), _), S(src, src_d)) => match src {
|
||||||
ast::Item::Symbol(Sym::Ident(ident)) => {
|
ast::Item::Symbol(Sym::Ident(ident)) => {
|
||||||
if !states.contains(ident) {
|
|
||||||
logs.emit_error("initial state symbol not defined as a state", *src_d);
|
|
||||||
}
|
|
||||||
if initial_state.is_some() {
|
if initial_state.is_some() {
|
||||||
logs.emit_error("initial state already set", *span);
|
logs.emit_error("initial state already set", *span);
|
||||||
}
|
}
|
||||||
initial_state = Some(ident)
|
if let Some(initial) = states.get(ident) {
|
||||||
|
initial_state = Some(*initial)
|
||||||
|
} else {
|
||||||
|
logs.emit_error("initial state symbol not defined as a state", *src_d);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => logs.emit_error("expected ident", *src_d),
|
_ => logs.emit_error("expected ident", *src_d),
|
||||||
},
|
},
|
||||||
TL::Assignment(S(Dest::Ident("S" | "z0"), _), S(src, src_d)) => match src {
|
TL::Assignment(S(Dest::Ident("S" | "z0"), _), S(src, src_d)) => match src {
|
||||||
ast::Item::Symbol(Sym::Ident(ident)) => {
|
ast::Item::Symbol(Sym::Ident(ident)) => {
|
||||||
if !stack_symbols.contains(ident)
|
if initial_stack.is_some() {
|
||||||
{
|
logs.emit_error("initial stack already set", *span);
|
||||||
|
}
|
||||||
|
if let Some(initial) = stack_symbols.get(ident) {
|
||||||
|
initial_stack = Some(*initial)
|
||||||
|
} else {
|
||||||
logs.emit_error(
|
logs.emit_error(
|
||||||
"initial stack symbol not defined as a stack symbol",
|
"initial stack symbol not defined as a stack symbol",
|
||||||
*src_d,
|
*src_d,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if initial_stack.is_some() {
|
|
||||||
logs.emit_error("initial stack already set", *span);
|
|
||||||
}
|
|
||||||
initial_stack = Some(ident)
|
|
||||||
}
|
}
|
||||||
_ => logs.emit_error("expected ident", *src_d),
|
_ => logs.emit_error("expected ident", *src_d),
|
||||||
},
|
},
|
||||||
|
|
@ -264,17 +293,38 @@ impl TransitionTable {
|
||||||
list,
|
list,
|
||||||
) => {
|
) => {
|
||||||
let list = list.set_weak();
|
let list = list.set_weak();
|
||||||
let Some((state, letter, sym)) =
|
let Some((state, letter, stack_symbol)) =
|
||||||
tuple.as_ref().expect_npda_transition_function(&mut logs)
|
tuple.as_ref().expect_npda_transition_function(&mut logs)
|
||||||
else {
|
else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
if !states.contains(state.0){
|
let Some(state) = states.get(state.0).copied() else{
|
||||||
logs.emit_error("transition state not defined as state", state.1);
|
logs.emit_error("transition state not defined as state", state.1);
|
||||||
}
|
continue;
|
||||||
if !stack_symbols.contains(sym.0){
|
};
|
||||||
logs.emit_error("transition stack symbol not defined as stack symbol", sym.1);
|
let Some(stack_symbol) = stack_symbols.get(stack_symbol.0).copied() else {
|
||||||
}
|
logs.emit_error(
|
||||||
|
"transition stack symbol not defined as stack symbol",
|
||||||
|
stack_symbol.1,
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
let char = match letter.0 {
|
||||||
|
Sym::Epsilon => None,
|
||||||
|
Sym::Ident(val) => if let Some(char) = val.chars().next() && val.chars().count() == 1 {
|
||||||
|
if !alphabet.contains(&char){
|
||||||
|
logs.emit_error("transition letter not defined in alphabet", letter.1);
|
||||||
|
}
|
||||||
|
Some(char)
|
||||||
|
}else{
|
||||||
|
logs.emit_error(
|
||||||
|
"transition letter can only be single character",
|
||||||
|
letter.1,
|
||||||
|
);
|
||||||
|
None
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
for item in list {
|
for item in list {
|
||||||
let Some((next_state, stack)) = item
|
let Some((next_state, stack)) = item
|
||||||
|
|
@ -284,9 +334,28 @@ impl TransitionTable {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
if !states.contains(next_state.0){
|
let Some(next_state) = states.get(next_state.0).copied() else {
|
||||||
logs.emit_error("transition state not defined as state", next_state.1);
|
logs.emit_error("transition state not defined as state", next_state.1);
|
||||||
}
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
let stack: Vec<_> = stack.iter().rev().filter_map(|symbol|{
|
||||||
|
if matches!(symbol.0, ast::Item::Symbol(Sym::Epsilon)) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let ident = symbol.expect_ident(&mut logs)?;
|
||||||
|
|
||||||
|
let Some(symbol) = stack_symbols.get(ident).copied() else{
|
||||||
|
logs.emit_error("transition stack symbol not defined", symbol.1);
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
Some(symbol)
|
||||||
|
}).collect();
|
||||||
|
|
||||||
|
transitions_map
|
||||||
|
.entry((state, char, stack_symbol))
|
||||||
|
.or_insert(Vec::new())
|
||||||
|
.push((next_state, stack))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TL::Assignment(S(Dest::Function(S(name, _), _), dest_s), _) => {
|
TL::Assignment(S(Dest::Function(S(name, _), _), dest_s), _) => {
|
||||||
|
|
@ -303,15 +372,87 @@ impl TransitionTable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if stack_symbols.is_empty() {
|
||||||
|
logs.emit_error_locless("stack symbols never defined");
|
||||||
|
}
|
||||||
|
|
||||||
|
if alphabet.is_empty() {
|
||||||
|
logs.emit_error_locless("alphabet never defined");
|
||||||
|
}
|
||||||
|
|
||||||
|
if states.is_empty() {
|
||||||
|
logs.emit_error_locless("states never defined");
|
||||||
|
}
|
||||||
|
|
||||||
|
let initial_stack = match initial_stack {
|
||||||
|
Some(some) => some,
|
||||||
|
None => {
|
||||||
|
if let Some(initial) = stack_symbols.get("z0") {
|
||||||
|
logs.emit_warning_locless(
|
||||||
|
"initial stack symbol not defined, defaulting to 'z0'",
|
||||||
|
);
|
||||||
|
*initial
|
||||||
|
} else {
|
||||||
|
logs.emit_error_locless("initial stack symbol not defined");
|
||||||
|
Symbol(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let initial_state = match initial_state {
|
||||||
|
Some(some) => some,
|
||||||
|
None => {
|
||||||
|
if let Some(initial) = states.get("z0") {
|
||||||
|
logs.emit_warning_locless("initial state not defined, defaulting to 'q0'");
|
||||||
|
*initial
|
||||||
|
} else {
|
||||||
|
logs.emit_error_locless("initial state not defined");
|
||||||
|
State(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let state_names = StateMap(states.iter().fold(
|
||||||
|
vec![String::new(); states.len()],
|
||||||
|
|mut a, (k, v)| {
|
||||||
|
a[v.0 as usize] = k.to_string();
|
||||||
|
a
|
||||||
|
},
|
||||||
|
));
|
||||||
|
let symbol_names = SymbolMap(stack_symbols.iter().fold(
|
||||||
|
vec![String::new(); stack_symbols.len()],
|
||||||
|
|mut a, (k, v)| {
|
||||||
|
a[v.0 as usize] = k.to_string();
|
||||||
|
a
|
||||||
|
},
|
||||||
|
));
|
||||||
|
let final_states = final_states.map(|f|{
|
||||||
|
StateMap(f.iter().fold(vec![false; states.len()], |mut a, k|{
|
||||||
|
a[k.0 as usize] = true;
|
||||||
|
a
|
||||||
|
}))
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut transitions: StateSymbolMap<CharEpsilonMap<Vec<To>>> = StateSymbolMap{
|
||||||
|
map: vec![CharEpsilonMap::default(); stack_symbols.len() * states.len()],
|
||||||
|
max_state: states.len() as u16,
|
||||||
|
};
|
||||||
|
|
||||||
|
for ((q, c, s), to) in transitions_map{
|
||||||
|
let from = &mut transitions[(q, s)];
|
||||||
|
for (n, ss) in to{
|
||||||
|
from.get_mut_or_insert_default(c).push(To(n, ss));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let table = TransitionTable {
|
let table = TransitionTable {
|
||||||
initial_state: crate::automata::State(0),
|
initial_state,
|
||||||
initial_stack: crate::automata::Symbol(0),
|
initial_stack,
|
||||||
state_names: Vec::new(),
|
state_names,
|
||||||
symbol_names: Vec::new(),
|
symbol_names,
|
||||||
alphabet: HashSet::new(),
|
alphabet,
|
||||||
accept_empty: false,
|
final_states,
|
||||||
final_states: Vec::new(),
|
transitions,
|
||||||
transitions: Default::default(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok((table, logs))
|
Ok((table, logs))
|
||||||
|
|
|
||||||
|
|
@ -26,10 +26,18 @@ impl<'a> Logs<'a> {
|
||||||
self.logs.push(entry);
|
self.logs.push(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn emit_error_locless(&mut self, msg: impl Into<String>) {
|
||||||
|
self.emit(LogEntry {
|
||||||
|
message: msg.into(),
|
||||||
|
span: None,
|
||||||
|
level: LogLevel::Error,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
pub fn emit_error(&mut self, msg: impl Into<String>, span: Span) {
|
pub fn emit_error(&mut self, msg: impl Into<String>, span: Span) {
|
||||||
self.emit(LogEntry {
|
self.emit(LogEntry {
|
||||||
message: msg.into(),
|
message: msg.into(),
|
||||||
span,
|
span: Some(span),
|
||||||
level: LogLevel::Error,
|
level: LogLevel::Error,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -37,7 +45,15 @@ impl<'a> Logs<'a> {
|
||||||
pub fn emit_warning(&mut self, msg: impl Into<String>, span: Span) {
|
pub fn emit_warning(&mut self, msg: impl Into<String>, span: Span) {
|
||||||
self.emit(LogEntry {
|
self.emit(LogEntry {
|
||||||
message: msg.into(),
|
message: msg.into(),
|
||||||
span,
|
span: Some(span),
|
||||||
|
level: LogLevel::Warning,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn emit_warning_locless(&mut self, msg: impl Into<String>) {
|
||||||
|
self.emit(LogEntry {
|
||||||
|
message: msg.into(),
|
||||||
|
span: None,
|
||||||
level: LogLevel::Warning,
|
level: LogLevel::Warning,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -45,7 +61,7 @@ impl<'a> Logs<'a> {
|
||||||
pub fn emit_info(&mut self, msg: impl Into<String>, span: Span) {
|
pub fn emit_info(&mut self, msg: impl Into<String>, span: Span) {
|
||||||
self.emit(LogEntry {
|
self.emit(LogEntry {
|
||||||
message: msg.into(),
|
message: msg.into(),
|
||||||
span,
|
span: Some(span),
|
||||||
level: LogLevel::Info,
|
level: LogLevel::Info,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -66,7 +82,7 @@ pub enum LogLevel {
|
||||||
|
|
||||||
pub struct LogEntry {
|
pub struct LogEntry {
|
||||||
pub message: String,
|
pub message: String,
|
||||||
pub span: Span,
|
pub span: Option<Span>,
|
||||||
pub level: LogLevel,
|
pub level: LogLevel,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -93,61 +109,53 @@ impl<'a> Display for LogEntryDisplay<'a> {
|
||||||
}
|
}
|
||||||
writeln!(f, "{}{RESET}", self.entry.message)?;
|
writeln!(f, "{}{RESET}", self.entry.message)?;
|
||||||
|
|
||||||
let line_start = self
|
if let Some(span) = self.entry.span {
|
||||||
.src
|
let line_start = self.src.get(..=span.0).unwrap_or("").lines().count();
|
||||||
.get(..=self.entry.span.0)
|
let line_end = self.src.get(..span.1).unwrap_or("").lines().count();
|
||||||
.unwrap_or("")
|
|
||||||
.lines()
|
|
||||||
.count();
|
|
||||||
let line_end = self
|
|
||||||
.src
|
|
||||||
.get(..self.entry.span.1)
|
|
||||||
.unwrap_or("")
|
|
||||||
.lines()
|
|
||||||
.count();
|
|
||||||
|
|
||||||
let padding = line_end.ilog10() as usize;
|
let padding = line_end.ilog10() as usize;
|
||||||
|
|
||||||
let start = self
|
let start = self
|
||||||
.src
|
.src
|
||||||
.get(..self.entry.span.0)
|
.get(..span.0)
|
||||||
.and_then(|s| s.rfind('\n'))
|
.and_then(|s| s.rfind('\n'))
|
||||||
.map(|v| v + 1)
|
.map(|v| v + 1)
|
||||||
.unwrap_or(0);
|
.unwrap_or(0);
|
||||||
|
|
||||||
let end = self
|
let end = self
|
||||||
.src
|
.src
|
||||||
.get(self.entry.span.1..)
|
.get(span.1..)
|
||||||
.and_then(|s| s.find('\n'))
|
.and_then(|s| s.find('\n'))
|
||||||
.map(|v| v + self.entry.span.1)
|
.map(|v| v + span.1)
|
||||||
.unwrap_or(self.src.len());
|
.unwrap_or(self.src.len());
|
||||||
|
|
||||||
let mut index = start;
|
let mut index = start;
|
||||||
for (i, line) in self.src.get(start..end).unwrap_or("").lines().enumerate() {
|
for (i, line) in self.src.get(start..end).unwrap_or("").lines().enumerate() {
|
||||||
write!(f, "{BOLD}{CYAN}{:>padding$}: {RESET}", i + line_start)?;
|
write!(f, "{BOLD}{CYAN}{:>padding$}: {RESET}", i + line_start)?;
|
||||||
for char in line.chars() {
|
for char in line.chars() {
|
||||||
if char == '\t' {
|
if char == '\t' {
|
||||||
write!(f, " ")?
|
write!(f, " ")?
|
||||||
} else {
|
} else {
|
||||||
write!(f, "{char}")?
|
write!(f, "{char}")?
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
writeln!(f)?;
|
||||||
writeln!(f)?;
|
write!(f, "{BOLD}{CYAN}")?;
|
||||||
write!(f, "{BOLD}{CYAN}")?;
|
for _ in 0..padding + 3 {
|
||||||
for _ in 0..padding + 3 {
|
|
||||||
write!(f, " ")?;
|
|
||||||
}
|
|
||||||
for char in line.chars() {
|
|
||||||
if (self.entry.span.0..self.entry.span.1).contains(&index) {
|
|
||||||
write!(f, "~")?;
|
|
||||||
} else {
|
|
||||||
write!(f, " ")?;
|
write!(f, " ")?;
|
||||||
}
|
}
|
||||||
index += char.len_utf8();
|
for char in line.chars() {
|
||||||
|
if (span.0..span.1).contains(&index) {
|
||||||
|
write!(f, "~")?;
|
||||||
|
} else {
|
||||||
|
write!(f, " ")?;
|
||||||
|
}
|
||||||
|
index += char.len_utf8();
|
||||||
|
}
|
||||||
|
write!(f, "{RESET}")?;
|
||||||
|
index += '\n'.len_utf8();
|
||||||
|
writeln!(f)?;
|
||||||
}
|
}
|
||||||
write!(f, "{RESET}")?;
|
|
||||||
index += '\n'.len_utf8();
|
|
||||||
writeln!(f)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,8 @@ use super::lexer::{Lexer, Token};
|
||||||
use std::iter::Peekable;
|
use std::iter::Peekable;
|
||||||
|
|
||||||
pub struct Parser<'a> {
|
pub struct Parser<'a> {
|
||||||
lexer: Peekable<Lexer<'a>>,
|
lexer: Lexer<'a>,
|
||||||
|
peek: Option<Spanned<Token<'a>>>,
|
||||||
logs: Logs<'a>,
|
logs: Logs<'a>,
|
||||||
src: &'a str,
|
src: &'a str,
|
||||||
eof: Span,
|
eof: Span,
|
||||||
|
|
@ -18,11 +19,15 @@ impl<'a> Parser<'a> {
|
||||||
eof: lexer.eof_span(),
|
eof: lexer.eof_span(),
|
||||||
src: lexer.input(),
|
src: lexer.input(),
|
||||||
logs: Logs::new(lexer.input()),
|
logs: Logs::new(lexer.input()),
|
||||||
lexer: lexer.peekable(),
|
peek: None,
|
||||||
|
lexer,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next_token(&mut self) -> Option<Spanned<Token<'a>>> {
|
fn next_token(&mut self) -> Option<Spanned<Token<'a>>> {
|
||||||
|
if self.peek.is_some(){
|
||||||
|
return self.peek.take()
|
||||||
|
}
|
||||||
loop {
|
loop {
|
||||||
match self.lexer.next()? {
|
match self.lexer.next()? {
|
||||||
Spanned(Ok(Token::Comment(_)), _) => {}
|
Spanned(Ok(Token::Comment(_)), _) => {}
|
||||||
|
|
@ -33,12 +38,10 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn peek_token(&mut self) -> Option<Spanned<Token<'a>>> {
|
fn peek_token(&mut self) -> Option<Spanned<Token<'a>>> {
|
||||||
loop {
|
if self.peek.is_none(){
|
||||||
match *self.lexer.peek()? {
|
self.peek = self.next_token();
|
||||||
Spanned(Ok(ok), r) => return Some(Spanned(ok, r)),
|
|
||||||
Spanned(Err(err), span) => self.logs.emit_error(format!("lexer: {err:?}"), span),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
self.peek
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expect_token(&mut self, expected: Token<'a>) -> (bool, Span) {
|
fn expect_token(&mut self, expected: Token<'a>) -> (bool, Span) {
|
||||||
|
|
@ -125,6 +128,7 @@ impl<'a> Parser<'a> {
|
||||||
Some(Spanned(Token::LPar, _)) => self.parse_tupple().map(Item::Tuple),
|
Some(Spanned(Token::LPar, _)) => self.parse_tupple().map(Item::Tuple),
|
||||||
Some(Spanned(Token::LBrace | Token::LBracket, _)) => self.parse_list().map(Item::List),
|
Some(Spanned(Token::LBrace | Token::LBracket, _)) => self.parse_list().map(Item::List),
|
||||||
Some(Spanned(got, span)) => {
|
Some(Spanned(got, span)) => {
|
||||||
|
self.next_token();
|
||||||
self.logs.emit_error(
|
self.logs.emit_error(
|
||||||
format!(
|
format!(
|
||||||
"unexpected token {:#}, expected {:}|{:}|{:}|{:}|{:}",
|
"unexpected token {:#}, expected {:}|{:}|{:}|{:}|{:}",
|
||||||
|
|
|
||||||
17
src/main.rs
17
src/main.rs
|
|
@ -17,4 +17,21 @@ fn main() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let input = "aababaab";
|
||||||
|
println!("running on: '{input}'");
|
||||||
|
let mut simulator = npda::Simulator::begin(input, table);
|
||||||
|
loop {
|
||||||
|
match simulator.step(){
|
||||||
|
npda::SimulatorResult::Pending => {},
|
||||||
|
npda::SimulatorResult::Reject => {
|
||||||
|
println!("REJECTED");
|
||||||
|
break;
|
||||||
|
},
|
||||||
|
npda::SimulatorResult::Accept(npda) => {
|
||||||
|
println!("ACCEPT: {npda:?}");
|
||||||
|
break;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue