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("F", _), list) => self.compile_final_states(list, span),
|
||||||
TL::Item(S(INITIAL_STATE, _), item) => self.compile_initial_state(item, span),
|
TL::Item(S(INITIAL_STATE, _), item) => self.compile_initial_state(item, span),
|
||||||
TL::Item(S(name, dest_s), _) => {
|
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) => {
|
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> {
|
pub struct PdaCompiler<'a, 'b> {
|
||||||
ctx: &'b mut Context<'a>,
|
ctx: &'b mut Context<'a>,
|
||||||
options: Options,
|
options: Options,
|
||||||
|
|
||||||
initial_state: Option<(State<'a>, Span)>,
|
initial_state: Option<(State<'a>, Span)>,
|
||||||
initial_stack: Option<(Symbol<'a>, Span)>,
|
initial_stack: Option<(Symbol<'a>, Span)>,
|
||||||
|
accept_by: Option<(AcceptBy, Span)>,
|
||||||
|
|
||||||
states: HashMap<State<'a>, StateInfo>,
|
states: HashMap<State<'a>, StateInfo>,
|
||||||
states_def: Option<Span>,
|
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> {
|
impl<'a, 'b> PdaCompiler<'a, 'b> {
|
||||||
pub fn new(ctx: &'b mut Context<'a>, options: Options) -> Self {
|
pub fn new(ctx: &'b mut Context<'a>, options: Options) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
|
@ -100,6 +119,7 @@ impl<'a, 'b> PdaCompiler<'a, 'b> {
|
||||||
|
|
||||||
initial_state: Default::default(),
|
initial_state: Default::default(),
|
||||||
initial_stack: Default::default(),
|
initial_stack: Default::default(),
|
||||||
|
accept_by: Default::default(),
|
||||||
states: Default::default(),
|
states: Default::default(),
|
||||||
states_def: Default::default(),
|
states_def: Default::default(),
|
||||||
symbols: 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)));
|
.emit_info_logless(concat!("G can be ", gamma_upper!(str)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// if self.final_states_def.is_none() {
|
if self.accept_by.is_none() {
|
||||||
// self.ctx
|
self.ctx
|
||||||
// .emit_error_locless("final states never defined")
|
.emit_error_locless("accept by never defined")
|
||||||
// .emit_help_logless("add: F = {...}");
|
.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 {
|
let initial_state = match self.initial_state {
|
||||||
Some(some) => some.0,
|
Some(some) => some.0,
|
||||||
|
|
@ -194,13 +235,16 @@ impl<'a, 'b> PdaCompiler<'a, 'b> {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let final_states =
|
||||||
|
matches!(self.accept_by, Some((AcceptBy::FinalState, _))).then_some(self.final_states);
|
||||||
|
|
||||||
Some(Pda {
|
Some(Pda {
|
||||||
initial_state,
|
initial_state,
|
||||||
initial_stack,
|
initial_stack,
|
||||||
states: self.states,
|
states: self.states,
|
||||||
symbols: self.symbols,
|
symbols: self.symbols,
|
||||||
alphabet: self.alphabet,
|
alphabet: self.alphabet,
|
||||||
final_states: Some(self.final_states),
|
final_states,
|
||||||
transitions: self.transitions,
|
transitions: self.transitions,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -209,6 +253,7 @@ impl<'a, 'b> PdaCompiler<'a, 'b> {
|
||||||
use Spanned as S;
|
use Spanned as S;
|
||||||
use ast::TopLevel as TL;
|
use ast::TopLevel as TL;
|
||||||
match element {
|
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("Q", _), list) => self.compile_states(list, span),
|
||||||
TL::Item(S(gamma_upper!(pat), _), list) => self.compile_symbols(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),
|
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_STATE, _), item) => self.compile_initial_state(item, span),
|
||||||
TL::Item(S(INITIAL_STACK, _), item) => self.compile_initial_stack(item, span),
|
TL::Item(S(INITIAL_STACK, _), item) => self.compile_initial_stack(item, span),
|
||||||
TL::Item(S(name, dest_s), _) => {
|
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) => {
|
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) {
|
fn compile_states(&mut self, list: Spanned<ast::Item<'a>>, top_level: Span) {
|
||||||
if let Some(previous) = self.states_def {
|
if let Some(previous) = self.states_def {
|
||||||
self.ctx
|
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(INITIAL_STATE, _), item) => self.compile_initial_state(item, span),
|
||||||
TL::Item(S(BLANK_SYMBOL, _), item) => self.compile_blank_symbol(item, span),
|
TL::Item(S(BLANK_SYMBOL, _), item) => self.compile_blank_symbol(item, span),
|
||||||
TL::Item(S(name, dest_s), _) => {
|
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) => {
|
TL::TransitionFunc(S((S(delta_lower!(pat), _), args), _), list) => {
|
||||||
|
|
|
||||||
|
|
@ -81,11 +81,12 @@ d(q4, 3) = q2`,
|
||||||
new Example(
|
new Example(
|
||||||
"DPDA",
|
"DPDA",
|
||||||
"unequal",
|
"unequal",
|
||||||
`type=DPDA
|
`type = DPDA
|
||||||
Q = {q0, qas, qeq, qmb, qlb} // states
|
Q = {q0, qas, qeq, qmb, qlb} // states
|
||||||
E = {a, b} // alphabet
|
E = {a, b} // alphabet
|
||||||
T = {z0, A} // stack
|
T = {z0, A} // stack
|
||||||
F = {qmb, qlb} // final states
|
F = {qmb, qlb} // final states
|
||||||
|
accept = F // accept by final state
|
||||||
q0 = q0
|
q0 = q0
|
||||||
z0 = z0
|
z0 = z0
|
||||||
|
|
||||||
|
|
@ -112,6 +113,7 @@ d(qmb, b, z0) = (qmb, z0)`,
|
||||||
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
|
||||||
|
accept = E // accept by empty stack
|
||||||
q0 = q0
|
q0 = q0
|
||||||
z0 = z0
|
z0 = z0
|
||||||
|
|
||||||
|
|
@ -142,6 +144,7 @@ d(q1, b, B) = { (q1, epsilon) }`,
|
||||||
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
|
||||||
|
accept = E // accept by empty stack
|
||||||
q0 = q0
|
q0 = q0
|
||||||
z0 = z0
|
z0 = z0
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue