mirror of
https://github.com/ParkerTenBroeck/automata.git
synced 2026-06-06 21:24:06 -04:00
added explicit accept by for PDAs
This commit is contained in:
parent
d6e4fff782
commit
ba996ee942
4 changed files with 89 additions and 19 deletions
|
|
@ -173,7 +173,7 @@ impl<'a, 'b> FaCompiler<'a, 'b> {
|
|||
TL::Item(S("F", _), list) => self.compile_final_states(list, span),
|
||||
TL::Item(S(INITIAL_STATE, _), item) => self.compile_initial_state(item, span),
|
||||
TL::Item(S(name, dest_s), _) => {
|
||||
self.ctx.emit_error(format!("unknown item {name:?}, expected states, alphabet, final states, initial state"), dest_s);
|
||||
self.ctx.emit_error(format!("unknown item {name:?}, expected states | alphabet | final states | initial state"), dest_s);
|
||||
}
|
||||
|
||||
TL::TransitionFunc(S((S(delta_lower!(pat), _), args), _), list) => {
|
||||
|
|
|
|||
|
|
@ -60,12 +60,19 @@ dual_struct_serde! { {#[serde_with::serde_as]}
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
enum AcceptBy {
|
||||
EmptyStack,
|
||||
FinalState,
|
||||
}
|
||||
|
||||
pub struct PdaCompiler<'a, 'b> {
|
||||
ctx: &'b mut Context<'a>,
|
||||
options: Options,
|
||||
|
||||
initial_state: Option<(State<'a>, Span)>,
|
||||
initial_stack: Option<(Symbol<'a>, Span)>,
|
||||
accept_by: Option<(AcceptBy, Span)>,
|
||||
|
||||
states: HashMap<State<'a>, StateInfo>,
|
||||
states_def: Option<Span>,
|
||||
|
|
@ -92,6 +99,18 @@ impl<'a> Pda<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
macro_rules! accept_empty {
|
||||
($ident: ident) => {
|
||||
$crate::maker!($ident: "N","n","null","empty","E","Z0","z0")
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! accept_final {
|
||||
($ident: ident) => {
|
||||
$crate::maker!($ident: "F","final")
|
||||
};
|
||||
}
|
||||
|
||||
impl<'a, 'b> PdaCompiler<'a, 'b> {
|
||||
pub fn new(ctx: &'b mut Context<'a>, options: Options) -> Self {
|
||||
Self {
|
||||
|
|
@ -100,6 +119,7 @@ impl<'a, 'b> PdaCompiler<'a, 'b> {
|
|||
|
||||
initial_state: Default::default(),
|
||||
initial_stack: Default::default(),
|
||||
accept_by: Default::default(),
|
||||
states: Default::default(),
|
||||
states_def: Default::default(),
|
||||
symbols: Default::default(),
|
||||
|
|
@ -140,11 +160,32 @@ impl<'a, 'b> PdaCompiler<'a, 'b> {
|
|||
.emit_info_logless(concat!("G can be ", gamma_upper!(str)));
|
||||
}
|
||||
|
||||
// if self.final_states_def.is_none() {
|
||||
// self.ctx
|
||||
// .emit_error_locless("final states never defined")
|
||||
// .emit_help_logless("add: F = {...}");
|
||||
// }
|
||||
if self.accept_by.is_none() {
|
||||
self.ctx
|
||||
.emit_error_locless("accept by never defined")
|
||||
.emit_help_logless("add: accept = N|F")
|
||||
.emit_info_logless(concat!(
|
||||
"accept by empty stack N can be ",
|
||||
accept_empty!(str)
|
||||
))
|
||||
.emit_info_logless(concat!(
|
||||
"accept by final state F can be ",
|
||||
accept_final!(str)
|
||||
));
|
||||
}
|
||||
|
||||
if self.final_states_def.is_none()
|
||||
&& matches!(self.accept_by, Some((AcceptBy::FinalState, _)))
|
||||
{
|
||||
self.ctx
|
||||
.emit_error_locless("final states never defined")
|
||||
.emit_help_logless("add: F = {...}");
|
||||
}else if let (Some((AcceptBy::EmptyStack, empty)), Some(states)) = (self.accept_by, self.final_states_def){
|
||||
self.ctx
|
||||
.emit_error_locless("final states defined alongside accept by empty stack")
|
||||
.emit_help("either remote to accept by empty stack", states)
|
||||
.emit_help("or remote to accept by final state", empty);
|
||||
}
|
||||
|
||||
let initial_state = match self.initial_state {
|
||||
Some(some) => some.0,
|
||||
|
|
@ -194,13 +235,16 @@ impl<'a, 'b> PdaCompiler<'a, 'b> {
|
|||
return None;
|
||||
}
|
||||
|
||||
let final_states =
|
||||
matches!(self.accept_by, Some((AcceptBy::FinalState, _))).then_some(self.final_states);
|
||||
|
||||
Some(Pda {
|
||||
initial_state,
|
||||
initial_stack,
|
||||
states: self.states,
|
||||
symbols: self.symbols,
|
||||
alphabet: self.alphabet,
|
||||
final_states: Some(self.final_states),
|
||||
final_states,
|
||||
transitions: self.transitions,
|
||||
})
|
||||
}
|
||||
|
|
@ -209,6 +253,7 @@ impl<'a, 'b> PdaCompiler<'a, 'b> {
|
|||
use Spanned as S;
|
||||
use ast::TopLevel as TL;
|
||||
match element {
|
||||
TL::Item(S("accept", _), item) => self.compile_accept_by(item, span),
|
||||
TL::Item(S("Q", _), list) => self.compile_states(list, span),
|
||||
TL::Item(S(gamma_upper!(pat), _), list) => self.compile_symbols(list, span),
|
||||
TL::Item(S(sigma_upper!(pat), _), list) => self.compile_alphabet(list, span),
|
||||
|
|
@ -216,7 +261,7 @@ impl<'a, 'b> PdaCompiler<'a, 'b> {
|
|||
TL::Item(S(INITIAL_STATE, _), item) => self.compile_initial_state(item, span),
|
||||
TL::Item(S(INITIAL_STACK, _), item) => self.compile_initial_stack(item, span),
|
||||
TL::Item(S(name, dest_s), _) => {
|
||||
self.ctx.emit_error(format!("unknown item {name:?}, expected states, stack symbols, alphabet, final states, initial state, initial stack"), dest_s);
|
||||
self.ctx.emit_error(format!("unknown item {name:?}, expected states | stack symbols | alphabet | accept by | final states | initial state | initial stack"), dest_s);
|
||||
}
|
||||
|
||||
TL::TransitionFunc(S((S(delta_lower!(pat), _), args), _), list) => {
|
||||
|
|
@ -239,6 +284,28 @@ impl<'a, 'b> PdaCompiler<'a, 'b> {
|
|||
}
|
||||
}
|
||||
|
||||
fn compile_accept_by(&mut self, item: Spanned<ast::Item<'a>>, top_level: Span) {
|
||||
if let Some((_, previous)) = self.accept_by {
|
||||
self.ctx
|
||||
.emit_error("accept by already set", top_level)
|
||||
.emit_info("previously defined here", previous);
|
||||
}
|
||||
let Some(by) = item.expect_ident(self.ctx) else {
|
||||
return;
|
||||
};
|
||||
|
||||
let by = match by {
|
||||
accept_empty!(pat) => AcceptBy::EmptyStack,
|
||||
accept_final!(pat) => AcceptBy::FinalState,
|
||||
_ => {
|
||||
self.ctx.emit_error("invalid accept by", item.1);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
self.accept_by = Some((by, top_level));
|
||||
}
|
||||
|
||||
fn compile_states(&mut self, list: Spanned<ast::Item<'a>>, top_level: Span) {
|
||||
if let Some(previous) = self.states_def {
|
||||
self.ctx
|
||||
|
|
|
|||
|
|
@ -190,7 +190,7 @@ impl<'a, 'b> TmCompiler<'a, 'b> {
|
|||
TL::Item(S(INITIAL_STATE, _), item) => self.compile_initial_state(item, span),
|
||||
TL::Item(S(BLANK_SYMBOL, _), item) => self.compile_blank_symbol(item, span),
|
||||
TL::Item(S(name, dest_s), _) => {
|
||||
self.ctx.emit_error(format!("unknown item {name:?}, expected states, symbols, final states, initial state, blank symbol"), dest_s);
|
||||
self.ctx.emit_error(format!("unknown item {name:?}, expected states | symbols | final states | initial state | blank symbol"), dest_s);
|
||||
}
|
||||
|
||||
TL::TransitionFunc(S((S(delta_lower!(pat), _), args), _), list) => {
|
||||
|
|
|
|||
|
|
@ -27,11 +27,11 @@ export const examples: readonly Example[] = [
|
|||
"DFA",
|
||||
`// strings over a,b which start and end with different letters
|
||||
|
||||
type = DFA // type of machine DFA, NFA, DPDA, NPDA, DTM, NTM
|
||||
Q = {q0, qa, qa', qb, qb'} // set of states
|
||||
E = {a, b} // alphabet
|
||||
F = {qa', qb'} // set of final states
|
||||
q0 = q0 // initial state
|
||||
type = DFA // type of machine DFA, NFA, DPDA, NPDA, DTM, NTM
|
||||
Q = {q0, qa, qa', qb, qb'} // set of states
|
||||
E = {a, b} // alphabet
|
||||
F = {qa', qb'} // set of final states
|
||||
q0 = q0 // initial state
|
||||
|
||||
// transition function (state, letter) -> state
|
||||
d(q0, a) = qa
|
||||
|
|
@ -81,11 +81,12 @@ d(q4, 3) = q2`,
|
|||
new Example(
|
||||
"DPDA",
|
||||
"unequal",
|
||||
`type=DPDA
|
||||
Q = {q0, qas, qeq, qmb, qlb} // states
|
||||
E = {a, b} // alphabet
|
||||
T = {z0, A} // stack
|
||||
F = {qmb, qlb} // final states
|
||||
`type = DPDA
|
||||
Q = {q0, qas, qeq, qmb, qlb} // states
|
||||
E = {a, b} // alphabet
|
||||
T = {z0, A} // stack
|
||||
F = {qmb, qlb} // final states
|
||||
accept = F // accept by final state
|
||||
q0 = q0
|
||||
z0 = z0
|
||||
|
||||
|
|
@ -112,6 +113,7 @@ d(qmb, b, z0) = (qmb, z0)`,
|
|||
Q = {q0, q1} // states
|
||||
E = {a, b} // alphabet
|
||||
T = {z0, A, B} // stack
|
||||
accept = E // accept by empty stack
|
||||
q0 = q0
|
||||
z0 = z0
|
||||
|
||||
|
|
@ -142,6 +144,7 @@ d(q1, b, B) = { (q1, epsilon) }`,
|
|||
Q = {q0, q1} // states
|
||||
E = {a, b} // alphabet
|
||||
T = {z0, A, B} // stack
|
||||
accept = E // accept by empty stack
|
||||
q0 = q0
|
||||
z0 = z0
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue