This commit is contained in:
Parker TenBroeck 2026-01-05 14:46:47 -05:00
parent f1b8c08e8f
commit 7971c61c74
15 changed files with 41485 additions and 252 deletions

View file

@ -7,13 +7,13 @@ pub mod npda;
pub mod ntm;
pub mod tm;
pub trait Get<Idx>{
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>{
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;
@ -67,7 +67,6 @@ pub struct State(u16);
#[derive(Clone, Debug, Copy, Hash, PartialEq, Eq)]
pub struct Symbol(u16);
#[derive(Clone, Debug)]
pub struct StateMap<T>(Vec<T>);
@ -84,18 +83,42 @@ pub struct StateSymbolMap<T> {
max_state: u16,
}
index!(StateSymbolMap, self, self.map, state.0 as usize + self.max_state as usize * symbol.0 as usize, (state, symbol) = (State, Symbol));
index!(StateSymbolMap, self, self.map, state.0 as usize + self.max_state as usize * symbol.0 as usize, (symbol, state) = (Symbol, State));
index!(
StateSymbolMap,
self,
self.map,
state.0 as usize + self.max_state as usize * symbol.0 as usize,
(state, symbol) = (State, Symbol)
);
index!(
StateSymbolMap,
self,
self.map,
state.0 as usize + self.max_state as usize * symbol.0 as usize,
(symbol, state) = (Symbol, State)
);
#[derive(Clone, Debug, Default)]
pub struct CharMap<T>(HashMap<char, T>);
index!(CharMap, self, self.0, &char, char = char, self.0.entry(char).or_default());
index!(
CharMap,
self,
self.0,
&char,
char = char,
self.0.entry(char).or_default()
);
#[derive(Clone, Debug, Default)]
pub struct CharEpsilonMap<T>(HashMap<Option<char>, T>);
index!(CharEpsilonMap, self, self.0, &Some(char), char = char, self.0.entry(Some(char)).or_default());
index!(CharEpsilonMap, self, self.0, &char, char = Option<char>, self.0.entry(char).or_default());
index!(
CharEpsilonMap,
self,
self.0,
&Some(char),
char = char,
self.0.entry(Some(char)).or_default()
);
index!(CharEpsilonMap, self, self.0, &char, char = Option<char>, self.0.entry(char).or_default());

View file

@ -31,15 +31,14 @@ pub struct Simulator {
running: Vec<NPDA>,
}
pub enum SimulatorResult{
pub enum SimulatorResult {
Pending,
Reject,
Accept(NPDA)
Accept(NPDA),
}
impl Simulator {
pub fn begin(input: impl Into<String>, table: TransitionTable) -> Self {
Self {
input: input.into(),
running: vec![NPDA {
@ -110,9 +109,9 @@ impl Simulator {
}
}
self.running = new;
if self.running.is_empty(){
if self.running.is_empty() {
SimulatorResult::Reject
}else{
} else {
SimulatorResult::Pending
}
}
@ -153,10 +152,9 @@ impl TransitionTable {
for Spanned(element, span) in ast {
use Spanned as S;
use ast::Dest;
use ast::TopLevel as TL;
match element {
TL::Assignment(S(Dest::Ident("Q"), _), list) => {
TL::Item(S("Q", _), list) => {
if !states.is_empty() {
logs.emit_error("states already set", *span);
}
@ -183,7 +181,7 @@ impl TransitionTable {
logs.emit_error("states cannot be empty", *span);
}
}
TL::Assignment(S(Dest::Ident("E" | SIGMA_UPPER | "sigma"), _), list) => {
TL::Item(S("E" | SIGMA_UPPER | "sigma", _), list) => {
if !alphabet.is_empty() {
logs.emit_error("alphabet already set", *span);
}
@ -207,7 +205,7 @@ impl TransitionTable {
logs.emit_error("alphabet cannot be empty", *span);
}
}
TL::Assignment(S(Dest::Ident("F"), _), list) => {
TL::Item(S("F", _), list) => {
if final_states.is_some() {
logs.emit_error("final states already set", *span);
}
@ -219,17 +217,17 @@ impl TransitionTable {
let Some(ident) = item.expect_ident(&mut logs) else {
continue;
};
if let Some(state) = states.get(ident){
if let Some(state) = states.get(ident) {
if !map.insert(*state) {
logs.emit_error("final state redefined", item.1);
}
} else{
} else {
logs.emit_error("final state not defined in set of states", item.1);
}
}
final_states = Some(map);
}
TL::Assignment(S(Dest::Ident("T" | GAMMA_UPPER | "gamma"), _), list) => {
TL::Item(S("T" | GAMMA_UPPER | "gamma", _), list) => {
if !stack_symbols.is_empty() {
logs.emit_error("stack symbols already set", *span);
}
@ -256,7 +254,7 @@ impl TransitionTable {
logs.emit_error("stack symbols cannot be empty", *span);
}
}
TL::Assignment(S(Dest::Ident("I" | "q0"), _), S(src, src_d)) => match src {
TL::Item(S("I" | "q0", _), S(src, src_d)) => match src {
ast::Item::Symbol(Sym::Ident(ident)) => {
if initial_state.is_some() {
logs.emit_error("initial state already set", *span);
@ -269,7 +267,7 @@ impl TransitionTable {
}
_ => logs.emit_error("expected ident", *src_d),
},
TL::Assignment(S(Dest::Ident("S" | "z0"), _), S(src, src_d)) => match src {
TL::Item(S("S" | "z0", _), S(src, src_d)) => match src {
ast::Item::Symbol(Sym::Ident(ident)) => {
if initial_stack.is_some() {
logs.emit_error("initial stack already set", *span);
@ -285,12 +283,12 @@ impl TransitionTable {
}
_ => logs.emit_error("expected ident", *src_d),
},
TL::Assignment(S(Dest::Ident(name), dest_s), _) => {
TL::Item(S(name, dest_s), _) => {
logs.emit_error(format!("unknown item {name:?}, expected 'Q'|'E'|'{SIGMA_UPPER}'|'sigma'|'F'|'T'|'{GAMMA_UPPER}'|'gamma'|'I'|'q0'|'S'|'z0'"), *dest_s);
}
TL::Assignment(
S(Dest::Function(S("d" | DELTA_LOWER | "delta", _), tuple), _),
TL::TransitionFunc(
S((S("d" | DELTA_LOWER | "delta", _), tuple), _),
list,
) => {
let list = list.set_weak();
@ -299,7 +297,7 @@ impl TransitionTable {
else {
continue;
};
let Some(state) = states.get(state.0).copied() else{
let Some(state) = states.get(state.0).copied() else {
logs.emit_error("transition state not defined as state", state.1);
continue;
};
@ -313,18 +311,25 @@ impl TransitionTable {
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);
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
}
Some(char)
}else{
logs.emit_error(
"transition letter can only be single character",
letter.1,
);
None
},
}
};
for item in list {
@ -339,29 +344,37 @@ impl TransitionTable {
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();
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();
if !transitions_map
.entry((state, char, stack_symbol))
.or_insert(HashSet::new())
.insert((next_state, stack)) {
logs.emit_warning("duplicate transition", item.1);
}
.insert((next_state, stack))
{
logs.emit_warning("duplicate transition", item.1);
}
}
}
TL::Assignment(S(Dest::Function(S(name, _), _), dest_s), _) => {
TL::TransitionFunc(S((S(name, _), _), dest_s), _) => {
logs.emit_error(
format!("unknown function {name:?}, expected 'd'|'delta'|'{DELTA_LOWER}'"),
*dest_s,
@ -429,21 +442,21 @@ impl TransitionTable {
a
},
));
let final_states = final_states.map(|f|{
StateMap(f.iter().fold(vec![false; states.len()], |mut a, k|{
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{
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{
for ((q, c, s), to) in transitions_map {
let from = &mut transitions[(q, s)];
for (n, ss) in to{
for (n, ss) in to {
from.get_mut_or_insert_default(c).push(To(n, ss));
}
}

View file

@ -2,6 +2,15 @@ use std::ops::Range;
use super::Spanned;
#[derive(Clone, Debug)]
pub enum ListKind {
Brace,
Bracket,
BraceComma,
BracketComma,
}
#[derive(Clone, Debug)]
pub struct Tuple<'a>(pub Vec<Spanned<Item<'a>>>);
@ -11,12 +20,6 @@ pub enum Symbol<'a> {
Ident(&'a str),
}
#[derive(Clone, Debug)]
pub enum Dest<'a> {
Ident(&'a str),
Function(Spanned<&'a str>, Spanned<Tuple<'a>>),
}
#[derive(Clone, Debug)]
pub enum Item<'a> {
Symbol(Symbol<'a>),
@ -40,12 +43,19 @@ pub enum Regex<'a> {
}
#[derive(Clone, Debug)]
pub struct List<'a>(pub Vec<Spanned<Item<'a>>>);
pub struct List<'a>(pub Vec<Spanned<Item<'a>>>, pub ListKind);
#[derive(Clone, Debug)]
pub struct ProductionGroup<'a>(pub Vec<Spanned<Symbol<'a>>>);
#[derive(Clone, Debug)]
pub enum TopLevel<'a> {
Assignment(Spanned<Dest<'a>>, Spanned<Item<'a>>),
ProductionRule(Spanned<Symbol<'a>>, Spanned<Symbol<'a>>),
Item(Spanned<&'a str>, Spanned<Item<'a>>),
TransitionFunc(Spanned<(Spanned<&'a str>, Spanned<Tuple<'a>>)>, Spanned<Item<'a>>),
ProductionRule(
Spanned<ProductionGroup<'a>>,
Spanned<Vec<Spanned<ProductionGroup<'a>>>>,
),
Table(),
}

View file

@ -26,13 +26,14 @@ pub enum Token<'a> {
Comment(&'a str),
Ident(&'a str),
LineEnd,
}
impl<'a> std::fmt::Display for Token<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Token::LPar => write!(f, "')'"),
Token::RPar => write!(f, "'('"),
Token::LPar => write!(f, "'('"),
Token::RPar => write!(f, "')'"),
Token::LBrace => write!(f, "'{{'"),
Token::RBrace => write!(f, "'}}'"),
Token::LBracket => write!(f, "'['"),
@ -49,6 +50,7 @@ impl<'a> std::fmt::Display for Token<'a> {
Token::Comment(_) => write!(f, "<comment>"),
Token::Ident(ident) if f.alternate() => write!(f, "{ident:?}"),
Token::Ident(_) => write!(f, "ident"),
Token::LineEnd => write!(f, "eol"),
}
}
}
@ -118,7 +120,15 @@ impl<'a> std::iter::Iterator for Lexer<'a> {
while let Some(c) = self.peek()
&& c.is_whitespace()
{
self.consume();
if c == '\n'{
self.start = self.position;
self.consume();
let res = Some(Spanned(Ok(Token::LineEnd), Span(self.start, self.position)));
self.start = self.position;
return res;
}else{
self.consume();
}
}
self.start = self.position;
@ -153,7 +163,8 @@ impl<'a> std::iter::Iterator for Lexer<'a> {
'/' => match self.consume() {
Some('/') => loop {
if let Some('\n') | None = self.consume() {
break Ok(Token::Comment(&self.input[self.start + 2..self.position]));
self.backtrack();
break Ok(Token::Comment(&self.input[self.start + 2..=self.position]));
}
},
Some('*') => loop {

View file

@ -73,15 +73,15 @@ impl<'a> Logs<'a> {
})
}
pub fn entries(&self) -> &[LogEntry]{
pub fn entries(&self) -> &[LogEntry] {
&self.logs
}
pub fn into_entries(self) -> impl Iterator<Item = LogEntry>{
pub fn into_entries(self) -> impl Iterator<Item = LogEntry> {
self.logs.into_iter()
}
pub fn src(&self) -> &str{
pub fn src(&self) -> &str {
&self.src
}
}
@ -134,15 +134,24 @@ impl<'a> Display for LogEntryDisplay<'a> {
.map(|v| v + 1)
.unwrap_or(0);
let end = self
.src
.get(span.1..)
.and_then(|s| s.find('\n'))
.map(|v| v + span.1)
.unwrap_or(self.src.len());
let end = if self.src.get(..span.1).unwrap_or("").ends_with("\n") {
span.1
} else {
self.src
.get(span.1..)
.and_then(|s| s.find('\n'))
.map(|v| v + span.1)
.unwrap_or(self.src.len())
};
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("")
.split_inclusive("\n")
.enumerate()
{
write!(f, "{BOLD}{CYAN}{:>padding$}: {RESET}", i + line_start)?;
for char in line.chars() {
if char == '\t' {
@ -151,7 +160,9 @@ impl<'a> Display for LogEntryDisplay<'a> {
write!(f, "{char}")?
}
}
writeln!(f)?;
if !line.ends_with("\n") {
writeln!(f)?;
}
write!(f, "{BOLD}{CYAN}")?;
for _ in 0..padding + 3 {
write!(f, " ")?;

View file

@ -1,12 +1,12 @@
use crate::loader::log::{LogEntryDisplay, Logs};
use crate::loader::{Span, Spanned};
use crate::loader::{EPSILON_LOWER, Span, Spanned};
use super::ast::*;
use super::lexer::{Lexer, Token};
pub struct Parser<'a> {
lexer: Lexer<'a>,
peek: Option<Spanned<Token<'a>>>,
peek: Spanned<Option<Token<'a>>>,
logs: Logs<'a>,
}
@ -14,30 +14,43 @@ impl<'a> Parser<'a> {
pub fn new(lexer: Lexer<'a>) -> Self {
Parser {
logs: Logs::new(lexer.input()),
peek: None,
peek: Spanned(None, Span(0,0)),
lexer,
}
}
pub fn eof(&self) -> Span{
fn eof(&self) -> Span {
self.lexer.eof_span()
}
fn next_token(&mut self) -> Option<Spanned<Token<'a>>> {
if self.peek.is_some(){
return self.peek.take()
fn advance_line(&mut self) {
if self.expect_token(Token::LineEnd).0 {
self.peek = Spanned(None, Span(0,0));
}
}
fn next_token(&mut self) -> Spanned<Option<Token<'a>>> {
match self.peek.0 {
Some(Token::LineEnd) => return self.peek,
Some(_) => return Spanned(self.peek.0.take(), self.peek.1),
_ => {}
}
loop {
match self.lexer.next()? {
Spanned(Ok(Token::Comment(_)), _) => {}
Spanned(Ok(ok), r) => return Some(Spanned(ok, r)),
Spanned(Err(err), span) => self.logs.emit_error(format!("lexer: {err:?}"), span),
match self.lexer.next() {
Some(Spanned(Ok(Token::Comment(_)), _)) => {}
Some(Spanned(Ok(Token::LineEnd), span)) => {
self.peek = Spanned(Some(Token::LineEnd), span);
return self.peek;
}
Some(Spanned(Ok(ok), r)) => return Spanned(Some(ok), r),
Some(Spanned(Err(err), span)) => self.logs.emit_error(format!("lexer: {err:?}"), span),
None => return Spanned(None, self.lexer.eof_span())
}
}
}
fn peek_token(&mut self) -> Option<Spanned<Token<'a>>> {
if self.peek.is_none(){
fn peek_token(&mut self) -> Spanned<Option<Token<'a>>> {
if self.peek.0.is_none() {
self.peek = self.next_token();
}
self.peek
@ -47,7 +60,7 @@ impl<'a> Parser<'a> {
if let Some(Spanned(token, span)) = self.peek_token() {
if token != expected {
self.logs.emit_error(
format!("unexpected token {:#}, expected {:}", token, expected),
format!("unexpected {:#}, expected {:}", token, expected),
span,
);
(false, span)
@ -56,22 +69,24 @@ impl<'a> Parser<'a> {
(true, span)
}
} else {
self.logs
.emit_error(format!("unexpected eof expected {:#}", expected), self.eof());
self.logs.emit_error(
format!("unexpected eof expected {:#}", expected),
self.eof(),
);
(false, self.eof())
}
}
pub fn parse_symbol(&mut self) -> Spanned<Symbol<'a>> {
fn parse_symbol(&mut self) -> Spanned<Symbol<'a>> {
match self.next_token() {
Some(Spanned(Token::Tilde, r)) => Spanned(Symbol::Epsilon, r),
Some(Spanned(Token::Ident("epsilon"), r)) => Spanned(Symbol::Epsilon, r),
Some(Spanned(Token::Ident(super::EPSILON_LOWER), r)) => Spanned(Symbol::Epsilon, r),
Some(Spanned(Token::Ident(ident), r)) => Spanned(Symbol::Ident(ident), r),
Some(Spanned(got, span)) => {
Spanned(Some(Token::Tilde), r) => Spanned(Symbol::Epsilon, r),
Spanned(Some(Token::Ident("epsilon")), r) => Spanned(Symbol::Epsilon, r),
Spanned(Some(Token::Ident(super::EPSILON_LOWER)), r) => Spanned(Symbol::Epsilon, r),
Spanned(Some(Token::Ident(ident)), r) => Spanned(Symbol::Ident(ident), r),
Spanned(Some(got), span) => {
self.logs.emit_error(
format!(
"unexpected token {:#}, expected {:}|{:}",
"unexpected token {:#}, expected {:}|{:} (symbol)",
got,
Token::Tilde,
Token::Ident("")
@ -80,21 +95,21 @@ impl<'a> Parser<'a> {
);
Spanned(Symbol::Ident("<INVALID>"), span)
}
None => {
Spanned(None, span) => {
self.logs.emit_error(
format!(
"unexpected eof expected {:}|{:}",
"unexpected eof expected {:}|{:} (symbol)",
Token::Tilde,
Token::Ident("")
),
self.eof(),
span,
);
Spanned(Symbol::Ident("<INVALID>"), self.eof())
}
}
}
pub fn parse_tupple(&mut self) -> Spanned<Tuple<'a>> {
fn parse_tupple(&mut self) -> Spanned<Tuple<'a>> {
let mut items = Vec::new();
let (matched, start) = self.expect_token(Token::LPar);
if !matched {
@ -106,12 +121,20 @@ impl<'a> Parser<'a> {
if matches!(self.peek_token(), Some(Spanned(Token::Comma, _))) {
self.next_token();
}
if self.peek_token().is_none() {
self.logs.emit_error(
format!("unexpected eof expected {:}", Token::RPar),
self.eof(),
);
break;
match self.peek_token() {
None => {
self.logs.emit_error(
format!("unexpected eof expected {:}", Token::RPar),
self.eof(),
);
return Spanned(Tuple(items), start.join(self.eof()));
}
Some(Spanned(Token::LineEnd, span)) => {
self.logs
.emit_error(format!("unexpected eol expected {:}", Token::RPar), span);
return Spanned(Tuple(items), start.join(span));
}
_ => {}
}
}
@ -120,7 +143,7 @@ impl<'a> Parser<'a> {
Spanned(Tuple(items), start.join(end))
}
pub fn parse_item(&mut self) -> Spanned<Item<'a>> {
fn parse_item(&mut self) -> Spanned<Item<'a>> {
match self.peek_token() {
Some(Spanned(Token::Ident(_) | Token::Tilde, _)) => {
self.parse_symbol().map(Item::Symbol)
@ -131,7 +154,7 @@ impl<'a> Parser<'a> {
self.next_token();
self.logs.emit_error(
format!(
"unexpected token {:#}, expected {:}|{:}|{:}|{:}|{:}",
"unexpected token {:#}, expected {:}|{:}|{:}|{:}|{:} (item)",
got,
Token::Tilde,
Token::Ident(""),
@ -146,7 +169,7 @@ impl<'a> Parser<'a> {
None => {
self.logs.emit_error(
format!(
"unexpected eof expected {:}|{:}|{:}|{:}|{:}",
"unexpected eof expected {:}|{:}|{:}|{:}|{:} (item)",
Token::Tilde,
Token::Ident(""),
Token::LPar,
@ -160,7 +183,7 @@ impl<'a> Parser<'a> {
}
}
pub fn parse_list(&mut self) -> Spanned<List<'a>> {
fn parse_list(&mut self) -> Spanned<List<'a>> {
let mut list = Vec::new();
let (start, match_end) = match self.next_token() {
@ -176,7 +199,7 @@ impl<'a> Parser<'a> {
),
span,
);
return Spanned(List(Vec::new()), span);
return Spanned(List(Vec::new(), ListKind::BracketComma), span);
}
None => {
self.logs.emit_error(
@ -187,65 +210,179 @@ impl<'a> Parser<'a> {
),
self.eof(),
);
return Spanned(List(Vec::new()), self.eof());
return Spanned(List(Vec::new(), ListKind::BracketComma), self.eof());
}
};
let mut comma = false;
while self.peek_token().map(|t| t.0) != Some(match_end) {
list.push(self.parse_item());
if matches!(self.peek_token(), Some(Spanned(Token::Comma, _))) {
comma = true;
self.next_token();
}
if self.peek_token().is_none() {
self.logs
.emit_error(format!("unexpected eof expected {:}", match_end), self.eof());
break;
match self.peek_token() {
None => {
self.logs.emit_error(
format!("unexpected eof expected {:}", match_end),
self.eof(),
);
return Spanned(List(list, ListKind::BraceComma), start.join(self.eof()));
}
Some(Spanned(Token::LineEnd, span)) => {
self.logs
.emit_error(format!("unexpected eol expected {:}", match_end), span);
return Spanned(List(list, ListKind::BraceComma), start.join(span));
}
_ => {}
}
}
let (_, end) = self.expect_token(match_end);
Spanned(List(list), start.join(end))
let kind = match (comma, match_end) {
(true, Token::RBrace) => ListKind::BraceComma,
(false, Token::RBrace) => ListKind::Brace,
(true, Token::RBracket) => ListKind::BracketComma,
(false, Token::RBracket) => ListKind::Bracket,
_ => unreachable!(),
};
Spanned(List(list, kind), start.join(end))
}
pub fn parse_regex(&mut self) -> Spanned<Regex<'a>> {
fn parse_regex(&mut self) -> Spanned<Regex<'a>> {
todo!()
}
fn parse_production_rule(
&mut self,
sym: Symbol<'a>,
start: Span,
) -> Option<Spanned<TopLevel<'a>>> {
let mut lhs_group = ProductionGroup(vec![Spanned(sym, start)]);
let mut lhs_group_end = start;
while !matches!(
self.peek_token(),
None | Some(Spanned(Token::LSmallArrow | Token::LineEnd, _))
) {
let sym = self.parse_symbol();
lhs_group_end = sym.1;
lhs_group.0.push(sym);
}
if !self.expect_token(Token::LSmallArrow).0{
return Some(Spanned(TopLevel::ProductionRule(Spanned(lhs_group, start.join(lhs_group_end)), Spanned(vec![], lhs_group_end)), start.join(lhs_group_end)))
}
let mut groups = Vec::new();
while !matches!(self.peek_token(), None | Some(Spanned(Token::LineEnd, _))){
let mut group = ProductionGroup(vec![]);
while !matches!(self.peek_token(), None | Some(Spanned(Token::LineEnd|Token::Or, _))){
group.0.push(self.parse_symbol());
}
if group.0.is_empty(){
let span = if let Some(Spanned(_, span)) = self.peek_token(){
span
}else{
self.eof()
};
self.logs.emit_error("cannot have empty production rule", span);
}
if matches!(self.peek_token(), Some(Spanned(Token::Or, _))){
self.next_token();
// if matches!(self.peek_token(), None|Spanned(Token::Or|Token::LineEnd))
}
let group_start = group.0.first().map(|g|g.1).unwrap_or(start);
let group_end = group.0.last().map(|g|g.1).unwrap_or(start);
groups.push(Spanned(group, group_start.join(group_end)))
}
if groups.is_empty(){
self.logs.emit_error("cannot have empty production rule", start.join(lhs_group_end));
}
let rules_start = groups.first().map(|f|f.1).unwrap_or(start);
let rules_end = groups.last().map(|f|f.1).unwrap_or(start);
Some(Spanned(TopLevel::ProductionRule(Spanned(lhs_group, start.join(lhs_group_end)), Spanned(groups, rules_start.join(rules_end))), start.join(rules_end)))
}
fn parse_transition_function(
&mut self,
ident: &'a str,
start: Span,
) -> Option<Spanned<TopLevel<'a>>> {
let tuple = self.parse_tupple();
let span = start.join(tuple.1);
let dest = Spanned((Spanned(ident, start), tuple), span);
if !self.expect_token(Token::Eq).0 {
return None;
}
let item = self.parse_item();
let span = start.join(item.1);
Some(Spanned(TopLevel::TransitionFunc(dest, item), span))
}
pub fn next_element(&mut self) -> Option<Spanned<TopLevel<'a>>> {
let result = loop {
let next = self.next_token()?;
match (next, self.peek_token()) {
(Spanned(Token::LineEnd, _), _) => self.advance_line(),
(Spanned(Token::Ident(ident), start), Some(Spanned(Token::LPar, _))) => {
if let Some(tf) = self.parse_transition_function(ident, start) {
break Some(tf);
}
}
(
Spanned(
Token::Ident(EPSILON_LOWER) | Token::Ident("epsilon") | Token::Tilde,
start,
),
Some(Spanned(Token::LSmallArrow | Token::Ident(_) | Token::Tilde, _)),
) => {
if let Some(pr) = self.parse_production_rule(Symbol::Epsilon, start) {
break Some(pr);
}
}
(
Spanned(Token::Ident(ident), start),
Some(Spanned(Token::LSmallArrow | Token::Ident(_) | Token::Tilde, _)),
) => {
if let Some(pr) = self.parse_production_rule(Symbol::Ident(ident), start) {
break Some(pr);
}
}
(Spanned(Token::Ident(ident), start), _) => {
let name = Spanned(ident, start);
if !self.expect_token(Token::Eq).0 {
continue;
}
let item = self.parse_item();
let span = start.join(item.1);
break Some(Spanned(TopLevel::Item(name, item), span));
}
_ => {
self.logs.emit_error(
format!(
"unexpected token {:#}, expected {:}",
next.0,
Token::Ident("")
),
next.1,
);
while !matches!(self.next_token(), None|Some(Spanned(Token::LineEnd, _))){
}
},
}
};
self.advance_line();
result
}
pub fn parse_elements(mut self) -> (Vec<Spanned<TopLevel<'a>>>, Logs<'a>) {
let mut result = Vec::new();
while let Some(next) = self.next_token() {
match (next, self.peek_token()) {
(Spanned(Token::Ident(ident), start), Some(Spanned(Token::LPar, _))) => {
let tuple = self.parse_tupple();
let span = start.join(tuple.1);
let dest = Spanned(Dest::Function(Spanned(ident, start), tuple), span);
if !self.expect_token(Token::Eq).0{continue;}
let item = self.parse_item();
let span = start.join(item.1);
result.push(Spanned(TopLevel::Assignment(dest, item), span));
}
(
Spanned(Token::Ident(_), start),
Some(Spanned(Token::LSmallArrow, end)),
) => {
self.logs.emit_error("Production rules are not yet supported", start.join(end));
}
(Spanned(Token::Ident(ident), start), _) => {
let dest = Spanned(Dest::Ident(ident), start);
if !self.expect_token(Token::Eq).0{continue;}
let item = self.parse_item();
let span = start.join(item.1);
result.push(Spanned(TopLevel::Assignment(dest, item), span));
}
_ => self.logs.emit_error(
format!(
"unexpected token {:#}, expected {:}",
next.0,
Token::Ident("")
),
next.1,
),
}
while let Some(next) = self.next_element() {
result.push(next)
}
(result, self.logs)

View file

@ -22,16 +22,16 @@ fn main() {
println!("running on: '{input}'");
let mut simulator = npda::Simulator::begin(input, table);
loop {
match simulator.step(){
npda::SimulatorResult::Pending => {},
match simulator.step() {
npda::SimulatorResult::Pending => {}
npda::SimulatorResult::Reject => {
println!("REJECTED");
break;
},
}
npda::SimulatorResult::Accept(npda) => {
println!("ACCEPT: {npda:?}");
break;
},
}
}
}
}