Skip to main content

lemon_mint/
lib.rs

1//! # lemon-mint
2//! Famous Lemon Parser Generator implemented in rust as library with API.
3//!
4//! ## Example
5//!
6//! ```
7//! use std::fs::File;
8//! use std::sync::Arc;
9//! use lemon_mint::LemonMintBuilder;
10//!
11//! fn main()
12//! {	let builder = LemonMintBuilder::new().load_y
13//! 	(	&Arc::new("source.y".to_string()), // fake source name, that will appear in error messages
14//! 		"	%trace {>> }
15//! 			%extra_argument {()}
16//! 			%left PLUS MINUS.
17//! 			%left TIMES DIVIDE.
18//! 			%token_type {f64}
19//! 			%type Expr {super::Expr}
20//! 			%type Exprs {Vec<super::Expr>}
21//! 			%type Program {Vec<super::Expr>}
22//!
23//! 			Program ::= Exprs(exprs). exprs
24//! 			Program ::= Exprs(exprs) NEW_LINE. exprs
25//!
26//! 			Exprs ::= Expr(item).                       vec![item]
27//! 			Exprs ::= Exprs(items) NEW_LINE Expr(item). let mut items = items; items.push(item); items
28//!
29//! 			Expr ::= NUM(value). super::Expr {value}
30//! 			Expr ::= PAR_OPEN Expr(a) PAR_CLOSE. a
31//! 			Expr ::= PLUS Expr(a). a
32//! 			Expr ::= MINUS Expr(a). let mut a = a; a.value = -a.value; a
33//! 			Expr ::= Expr(a) PLUS Expr(b). super::Expr{value: a.value + b.value}
34//! 			Expr ::= Expr(a) MINUS Expr(b). super::Expr{value: a.value - b.value}
35//! 			Expr ::= Expr(a) TIMES Expr(b). super::Expr{value: a.value * b.value}
36//! 			Expr ::= Expr(a) DIVIDE Expr(b). super::Expr{value: a.value / b.value}
37//!
38//! 			%code {
39//! 				use code::{Parser, Token};
40//!
41//!                 #[derive(Debug, PartialEq)]
42//! 				pub struct Expr {value: f64}
43//!
44//! 				fn main()
45//! 				{	let mut parser = Parser::new(()); // () is our extra argument, that will be accessible in actions, and also through parser.extra
46//!
47//! 					parser.add_token(Token::NUM, 15.0).unwrap();
48//! 					parser.add_token(Token::DIVIDE, 0.0).unwrap();
49//! 					parser.add_token(Token::NUM, 5.0).unwrap();
50//! 					parser.add_token(Token::NEW_LINE, 0.0).unwrap();
51//!
52//! 					let result = parser.end().unwrap(); // if Program
53//!                     assert_eq!(result, vec![Expr {value: 3.0}]);
54//!                     println!(\"Result: {:?}\", result);
55//! 				}
56//! 			}
57//! 		".as_bytes()
58//! 	).unwrap();
59//!
60//! 	let lemon = builder.try_into_lemon().unwrap();
61//! 	let mut out_rust = File::create("/tmp/main.rs").unwrap();
62//! 	let mut out_y = File::create("/tmp/main.y").unwrap();
63//! 	lemon.gen_rust(&mut out_rust).unwrap();
64//! 	lemon.gen_log(&mut out_y, false, false).unwrap();
65//! }
66//! ```
67//!
68//! The first step is to create `LemonMintBuilder` object, and use it's methods to describe the desired parser. It's possible to load "y"-grammar from a file with `load_y_file()`, or from a string with `load_y()`, as shown in the example above, or you can set each parser rule with individual methods, like `set_start_symbol()`, `set_token_type()`, `add_type()`, `add_rule()`, and others.
69//!
70//! Then the builder object can be converted to `LemonMint` object that represents the parser transition tables. This step is done with the `try_into_lemon()` method, as shown above.
71//!
72//! And the last step is to generate a rust file with parser tables and it's driver code. This is done with `gen_rust()` method. Optionally you can generate log file with `gen_log()`, as classic Lemon program does.
73//!
74//! ## Y-Grammar
75//!
76//! Lemon-mint uses y-grammar similar to what [classic Lemon parser](https://www.hwaci.com/sw/lemon/) uses. There are a few distinctions:
77//!
78//! * If a symbol name contains at least one lowercase letter, it's considered nonterminal. In classic Lemon only the first letter matters.
79//! * To enable trace, use `%trace` directive. In Lemon need to call ParseTrace() function.
80//! * No need for `%name` directive, because in rust each file is separate module.
81//! * No need for destructors.
82//!
83//! The generated parser will be separated to 2 submodules: `code` and `rules`. There are only 2 interesting things in `code` module: `Parser` and `Token`. See in above example how they're used. The `rules` module wraps actions, and you don't need to use it directly. If your actions use types, constants or functions global space, they can be accessed like `super::Expr`, or `crate::Expr`, or so.
84//!
85//! The following directives are supported:
86//!
87//! * %token_type
88//! * %type
89//! * %default_type
90//! * %start_symbol
91//! * %trace
92//! * %extra_argument - only it's type. The name is always `extra`. Default type is `()`.
93//! * %left
94//! * %right
95//! * %nonassoc
96//! * %fallback
97//! * %code or %include - are the same
98//!
99//! The syntax is free and permissive:
100//!
101//! ```ignore
102//! %start_symbol {Unit}
103//! /* or */
104//! %start_symbol Unit.
105//! /* or */
106//! %start_symbol Unit
107//! ```
108//!
109//! Braces allow to specify multiline value, till matching closing brace. Supported line and multiline C-style comments.
110
111
112mod lempar;
113
114use lempar::LemparReader;
115
116use std::mem;
117use std::cmp;
118use std::cmp::Ordering;
119use std::collections::HashMap;
120use std::cell::RefCell;
121use std::io::{self, BufRead, BufReader};
122use std::fmt;
123use std::hash::{Hash, Hasher};
124use std::collections::hash_map::DefaultHasher;
125use std::error::Error;
126use std::iter::Take;
127use std::slice::Iter;
128use std::convert::TryFrom;
129use std::rc::Rc;
130use std::sync::Arc;
131use std::fs::File;
132use std::borrow::Cow;
133
134fn typename_to_string(value: String) -> String
135{	let value_trimmed = value.trim();
136	if value_trimmed.is_empty() || value.starts_with('(') && value.ends_with(')') && value[1 .. value.len()-1].trim().is_empty()
137	{	String::new()
138	}
139	else
140	{	if value.len() == value_trimmed.len() {value} else {value_trimmed.to_string()}
141	}
142}
143
144fn is_terminal_name(s: &str) -> bool
145{	s.find(|c: char| c.is_ascii_lowercase()).is_none()
146}
147
148#[derive(Debug)]
149pub struct LemonMintError
150{	pub filename: Arc<String>,
151	pub n_line: usize,
152	pub message: String,
153}
154impl LemonMintError
155{	pub fn new(filename: &Arc<String>, n_line: usize, message: String) -> Self
156	{	Self {filename: Arc::clone(filename), n_line, message}
157	}
158}
159impl fmt::Display for LemonMintError
160{	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
161	{	let message: &str = if self.message.is_empty() {"Unspecified error"} else {&self.message};
162		if self.filename.is_empty()
163		{	write!(f, "{}", message)
164		}
165		else
166		{	write!(f, "{}({}): {}", self.filename, self.n_line, message)
167		}
168	}
169}
170impl Error for LemonMintError {}
171
172type ParserResult<T> = Result<T, LemonMintError>;
173
174#[derive(Copy, Clone, Eq, PartialEq, Debug)]
175enum Directive
176{	Rule,
177	TokenType,
178	Type,
179	DefaultType,
180	StartSymbol,
181	Trace,
182	ExtraArgument,
183	Left,
184	Right,
185	Nonassoc,
186	Fallback,
187	Code,
188}
189
190#[derive(Copy, Clone, Eq, PartialEq, Debug)]
191enum SymbolType
192{	TERMINAL,
193	NONTERMINAL
194}
195
196#[derive(Copy, Clone, Eq, PartialEq, Debug)]
197enum Associativity
198{	LEFT,
199	RIGHT,
200	NONASSOC,
201	UNKNOWN
202}
203
204#[derive(Debug)]
205struct Set
206{	data: Vec<bool>,
207}
208impl Set
209{	pub fn new(size: usize) -> Self
210	{	let mut this = Self {data: Vec::new()};
211		if size > 0
212		{	this.set_size(size);
213		}
214		this
215	}
216
217	pub fn len(&self) -> usize
218	{	self.data.len()
219	}
220
221	pub fn set_size(&mut self, size: usize)
222	{	self.data.clear();
223		self.data.resize(size, false);
224	}
225
226	pub fn contains(&self, element: usize) -> bool
227	{	*self.data.get(element).unwrap_or(&false)
228	}
229
230	pub fn add(&mut self, element: usize) -> bool
231	{	let rv = self.contains(element);
232		if let Some(v) = self.data.get_mut(element)
233		{	*v = true;
234		}
235		!rv
236	}
237
238	pub fn intersect(&mut self, other: &Set) -> bool
239	{	let mut changed = false;
240		for (i, v) in &mut self.data.iter_mut().enumerate()
241		{	if !*v && other.contains(i)
242			{	changed = true;
243				*v = true;
244			}
245		}
246		return changed;
247	}
248}
249
250/// Terminal or nonterminal symbol from the grammar.
251#[derive(Debug)]
252struct Symbol
253{	name: Arc<String>,             // Name of the symbol
254	index: usize,                  // Index number for this symbol
255	typ: SymbolType,               // Symbols are all either TERMINALS or NTs
256	sym_rules_arr: Vec<usize>,     // Array of rules of this (if an NT) (indices in rules array)
257	fallback_index: usize,         // fallback token in case this token doesn't parse
258	prec: i32,                     // Precedence if defined (-1 otherwise)
259	assoc: Associativity,          // Associativity if precedence is defined
260	firstset: Set,                 // First-set for all rules of this symbol
261	lambda: bool,                  // True if NT and can generate an empty string
262	data_type: String,             // The data type of information held by this object. Only used if type==NONTERMINAL
263	dtnum: usize,                  // The data type number. In the parser, the value stack is a union. The .Symbol%d element of this union is the correct data type for this object
264}
265impl Symbol
266{	fn new(name: &str, index: usize) -> Self
267	{	let typ = if is_terminal_name(name) || name=="$" {SymbolType::TERMINAL} else {SymbolType::NONTERMINAL};
268		Self
269		{	name: Arc::new(String::new()),
270			index,
271			typ,
272			sym_rules_arr: Vec::new(),
273			fallback_index: std::usize::MAX,
274			prec: -1,
275			assoc: Associativity::UNKNOWN,
276			firstset: Set::new(0),
277			lambda: false,
278			data_type: String::new(),
279			dtnum: 0,
280		}
281	}
282}
283impl PartialEq for Symbol
284{	fn eq(&self, other: &Self) -> bool
285	{	self.index == other.index
286	}
287}
288
289#[derive(Debug)]
290struct Rhs
291{	name: Arc<String>,
292	index: usize,
293	alias: String,
294}
295
296/// Each production rule in the grammar is stored in this structure.
297#[derive(Debug)]
298struct Rule
299{	rule_filename: Arc<String>,
300	rule_n_line: usize,            // Line number for the rule
301	lhs: Arc<String>,              // Left-hand side of the rule
302	lhs_index: usize,              // Left-hand side of the rule (index in symbols)
303	lhs_start: bool,               // True if left-hand side is the start symbol
304	rhs: Vec<Rhs>,                 // The RHS symbols
305	code: String,                  // The code executed when this rule is reduced
306	precsym_index: usize,          // Precedence symbol for this rule (index in symbols)
307	index: usize,                  // An index number for this rule
308	can_reduce: bool,              // True if this rule is ever reduced
309	does_reduce: bool,             // Reduce actions occur after optimization
310}
311impl Rule
312{	fn new(rule_filename: &Arc<String>, rule_n_line: usize, lhs: &Arc<String>, lhs_index: usize, index: usize, code: String) -> Self
313	{	Self
314		{	rule_filename: Arc::clone(rule_filename),
315			rule_n_line,
316			lhs: Arc::clone(lhs),
317			lhs_index,
318			lhs_start: false,
319			rhs: Vec::new(),
320			code,
321			precsym_index: std::usize::MAX,
322			index,
323			can_reduce: false,
324			does_reduce: false,
325		}
326	}
327}
328impl fmt::Display for Rule
329{	/// Write text on "out" that describes the rule
330	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
331	{	write!(f, "{} ::=", self.lhs)?;
332		for sp in &self.rhs
333		{	write!(f, " {}", sp.name)?;
334		}
335		Ok(())
336	}
337}
338
339#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
340struct ConfigKey
341{	n_rule: usize,
342	dot: usize,
343}
344impl ConfigKey
345{	fn new(config: &Config) -> Self
346	{	Self
347		{	n_rule: config.n_rule,
348			dot: config.dot,
349		}
350	}
351}
352impl cmp::Ord for ConfigKey
353{	fn cmp(&self, other: &Self) -> cmp::Ordering
354	{	let mut res = self.n_rule.cmp(&other.n_rule);
355		if res == Ordering::Equal
356		{	res = self.dot.cmp(&other.dot);
357		}
358		res
359	}
360}
361impl cmp::PartialOrd for ConfigKey
362{	fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering>
363	{	Some(self.cmp(other))
364	}
365}
366
367/// A configuration is a production rule of the grammar together with
368/// a mark (dot) showing how much of that rule has been processed so far.
369/// Configurations also contain a follow-set which is a list of terminal
370/// symbols which are allowed to immediately follow the end of the rule.
371/// Every configuration is recorded as an instance of this structure.
372#[derive(Debug)]
373struct Config
374{	n_rule: usize,                  // The rule upon which the configuration is based
375	dot: usize,                     // The parse point
376	fws: Set,                       // Follow-set for this configuration only
377	fplp: Vec<Rc<RefCell<Config>>>, // Follow-set forward propagation links
378	bplp: Vec<Rc<RefCell<Config>>>, // Follow-set backwards propagation links
379	n_state: usize,                 // Pointer to state which contains this
380	status_is_complete: bool,       // used during followset and shift computations
381}
382impl Config
383{	pub fn new(n_rule: usize, dot: usize, fws_size: usize) -> Self
384	{	Self
385		{	n_rule,
386			dot,
387			fws: Set::new(fws_size),
388			fplp: Vec::new(),
389			bplp: Vec::new(),
390			n_state: std::usize::MAX,
391			status_is_complete: false,
392		}
393	}
394}
395impl cmp::Ord for Config
396{	fn cmp(&self, other: &Self) -> cmp::Ordering
397	{	ConfigKey::new(self).cmp(&ConfigKey::new(other))
398	}
399}
400impl cmp::PartialOrd for Config
401{	fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering>
402	{	Some(self.cmp(other))
403	}
404}
405impl cmp::PartialEq for Config
406{	fn eq(&self, other: &Self) -> bool
407	{	ConfigKey::new(self).eq(&ConfigKey::new(other))
408	}
409}
410impl Eq for Config {}
411
412#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
413enum ActionType
414{	Shift,
415	Accept,
416	Reduce,
417	Error,
418	SsConflict,  // A shift/shift conflict
419	SrConflict,  // Was a reduce, but part of a conflict
420	RrConflict,  // Was a reduce, but part of a conflict
421	ShResolved, // Was a shift.  Precedence resolved conflict
422	RdResolved, // Was reduce.  Precedence resolved conflict
423	NotUsed,    // Deleted by compression
424	ShiftReduce // Shift first, then reduce
425}
426
427#[derive(Debug, PartialEq, Copy, Clone)]
428enum StateOrRule
429{	State(usize), // n_state: usize - The new state, if a shift
430	Rule(usize),  // The rule, if a reduce
431	EmptyRule     // Empty reduce rule for "accepting" token
432}
433
434/// Every shift or reduce operation is stored as one of this structure.
435#[derive(Debug)]
436struct Action
437{	id: i32,
438	symbol_index: usize,     // The look-ahead symbol
439	typ: ActionType,
440	x: StateOrRule,
441	symbol_index_opt: usize, // ActionType::ShiftReduce optimization to this symbol
442}
443impl Action
444{	fn new_state(id: i32, symbol_index: usize, n_state: usize) -> Action
445	{	Action
446		{	id,
447			symbol_index,
448			typ: ActionType::Shift,
449			x: StateOrRule::State(n_state),
450			symbol_index_opt: std::usize::MAX,
451		}
452	}
453
454	fn new_rule(id: i32, symbol_index: usize, typ: ActionType, n_rule: usize) -> Action
455	{	Action
456		{	id,
457			symbol_index,
458			typ,
459			x: StateOrRule::Rule(n_rule),
460			symbol_index_opt: std::usize::MAX,
461		}
462	}
463
464	fn new_empty_rule(id: i32, symbol_index: usize, typ: ActionType) -> Action
465	{	Action
466		{	id,
467			symbol_index,
468			typ,
469			x: StateOrRule::EmptyRule,
470			symbol_index_opt: std::usize::MAX,
471		}
472	}
473}
474impl cmp::Ord for Action
475{	fn cmp(&self, other: &Self) -> cmp::Ordering
476	{	let index = self.symbol_index;
477		let other_index = other.symbol_index;
478		let mut res = index.cmp(&other_index);
479		if res == Ordering::Equal
480		{	res = self.typ.cmp(&other.typ);
481			if res == Ordering::Equal
482			{	if self.typ==ActionType::Reduce || self.typ==ActionType::ShiftReduce
483				{	if let StateOrRule::Rule(n_rule) = self.x
484					{	if let StateOrRule::Rule(other_n_rule) = other.x
485						{	if n_rule < other_n_rule
486							{	return Ordering::Less;
487							}
488							if n_rule > other_n_rule
489							{	return Ordering::Greater;
490							}
491						}
492					}
493				}
494				res = self.id.cmp(&other.id);
495			}
496		}
497		res
498	}
499}
500impl cmp::PartialOrd for Action
501{	fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering>
502	{	Some(self.cmp(other))
503	}
504}
505impl cmp::PartialEq for Action
506{	fn eq(&self, other: &Self) -> bool
507	{	self.cmp(other) == Ordering::Equal
508	}
509}
510impl Eq for Action {}
511
512/// Each state of the generated parser's finite state machine is encoded as an instance of this structure.
513#[derive(Debug)]
514struct State
515{	basis: Vec<Rc<RefCell<Config>>>,          // The basis configurations for this state
516	configurations: Vec<Rc<RefCell<Config>>>, // All configurations in this set
517	n_state: usize,                    // Sequential number for this state
518	actions: Vec<Rc<RefCell<Action>>>, // Array of actions for this state
519	n_token_act: usize,
520	n_nt_act: usize,                   // Number of actions on terminals and nonterminals
521	token_offset: isize,
522	nt_offset: isize,                  // yy_action[] offset for terminals and nonterms
523	default_reduce_action: usize,      // Default action is to REDUCE by this rule
524	default_reduce_rule: usize,        // The default REDUCE rule
525	auto_reduce: bool,
526}
527impl State
528{	pub fn new(n_state: usize, basis: Vec<Rc<RefCell<Config>>>, configurations: Vec<Rc<RefCell<Config>>>) -> Self
529	{	Self
530		{	basis,
531			configurations,
532			n_state,
533			actions: Vec::new(),
534			n_token_act: 0,
535			n_nt_act: 0,
536			token_offset: 0,
537			nt_offset: 0,
538			default_reduce_action: 0,
539			default_reduce_rule: std::usize::MAX,
540			auto_reduce: false,
541		}
542	}
543}
544
545/// Each state contains a set of token transaction and a set of
546/// nonterminal transactions.  Each of these sets makes an instance
547/// of the following structure.  An array of these structures is used
548/// to order the creation of entries in the `yy_action[]` table.
549#[derive(Debug)]
550struct AxSet
551{	n_state: usize, // Index in sorted states array
552	is_tkn: bool,    // True to use tokens.  False for non-terminals
553	n_action: usize,   // Number of actions
554	i_order: usize,    // Original order of action sets
555}
556impl AxSet
557{	fn new(n_state: usize, is_tkn: bool, n_action: usize, i_order: usize) -> Self
558	{	Self
559		{	n_state,
560			is_tkn,
561			n_action,
562			i_order,
563		}
564	}
565}
566impl cmp::Ord for AxSet
567{	fn cmp(&self, other: &Self) -> cmp::Ordering
568	{	let mut res = other.n_action.cmp(&self.n_action); // descending order
569		if res == Ordering::Equal
570		{	res = self.i_order.cmp(&other.i_order);
571		}
572		res
573	}
574}
575impl cmp::PartialOrd for AxSet
576{	fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering>
577	{	Some(self.cmp(other))
578	}
579}
580impl cmp::PartialEq for AxSet
581{	fn eq(&self, other: &Self) -> bool
582	{	self.cmp(other) == Ordering::Equal
583	}
584}
585impl Eq for AxSet {}
586
587/// The state of the yy_action table under construction is an instance of
588/// the following structure.
589///
590/// The yy_action table maps the pair (state_number, lookahead) into an
591/// action_number.  The table is an array of integers pairs.  The state_number
592/// determines an initial offset into the yy_action array.  The lookahead
593/// value is then added to this initial offset to get an index X into the
594/// yy_action array. If the `aAction[X]`.lookahead equals the value of the
595/// of the lookahead input, then the value of the action_number output is
596/// `aAction[X].action`.  If the lookaheads do not match then the
597/// default action for the state_number is returned.
598///
599/// All actions associated with a single state_number are first entered
600/// into `aLookahead[]` using multiple calls to acttab_action().  Then the
601/// actions for that single state_number are placed into the `aAction[]`
602/// array with a single call to acttab_insert().  The acttab_insert() call
603/// also resets the `aLookahead[]` array in preparation for the next
604/// state number.
605#[derive(Copy, Clone, Eq, PartialEq, Debug)]
606struct LookaheadAction
607{	lookahead: usize, // Value of the lookahead token
608	action: usize,    // Action to take on the given lookahead
609}
610impl LookaheadAction
611{	fn new(lookahead: usize, action: usize) -> Self
612	{	Self
613		{	lookahead,
614			action,
615		}
616	}
617}
618
619#[derive(Debug)]
620struct ActTab
621{	n_action: usize,                   // Number of used slots in aAction[]
622	a_action: Vec<LookaheadAction>,    // The yy_action[] table under construction
623	a_lookahead: Vec<LookaheadAction>, // A single new transaction set
624	min_lookahead: usize,              // Minimum aLookahead[].lookahead
625	max_lookahead: usize,              // Maximum aLookahead[].lookahead
626	min_action: usize,                 // Action associated with mnLookahead
627
628	n_terminals: usize,                // Number of terminal symbols
629	n_symbols: usize,                  // Total number of symbols
630
631	min_token_offset: isize,
632	max_token_offset: isize,
633	min_nt_offset: isize,
634	max_nt_offset: isize,
635
636	n_fallbacks: usize,
637	n_shift_offset: usize,
638	reduce_count: usize,
639}
640impl ActTab
641{	fn new(n_terminals: usize, n_symbols: usize) -> Self
642	{	Self
643		{	n_action: 0,
644			a_action: Vec::new(),
645			a_lookahead: Vec::new(),
646			min_lookahead: 0,
647			max_lookahead: 0,
648			min_action: 0,
649
650			n_terminals,
651			n_symbols,
652
653			min_token_offset: 0,
654			max_token_offset: 0,
655			min_nt_offset: 0,
656			max_nt_offset: 0,
657
658			n_fallbacks: 0,
659			n_shift_offset: 0,
660			reduce_count: 0,
661		}
662	}
663
664	fn get_n_lookahead(&self) -> usize
665	{	self.n_action
666	}
667
668	fn get_n_actions(&self) -> usize
669	{	let mut n_action = self.n_action;
670		for rec in  self.a_action.iter().take(n_action).rev()
671		{	if rec.lookahead == std::usize::MAX
672			{	n_action -= 1;
673			}
674			else
675			{	break;
676			}
677		}
678		n_action
679	}
680
681	fn iter(&self) -> Take<Iter<'_, LookaheadAction>>
682	{	self.a_action.iter().take(self.n_action)
683	}
684
685	/// Add a new action to the current transaction set.
686	/// This routine is called once for each lookahead for a particular state.
687	fn acttab_action(&mut self, lookahead: usize, action: usize)
688	{	if self.a_lookahead.len() == 0
689		{	self.max_lookahead = lookahead;
690			self.min_lookahead = lookahead;
691			self.min_action = action;
692		}
693		else
694		{	if self.max_lookahead < lookahead
695			{	self.max_lookahead = lookahead;
696			}
697			if self.min_lookahead > lookahead
698			{	self.min_lookahead = lookahead;
699				self.min_action = action;
700			}
701		}
702		self.a_lookahead.push(LookaheadAction::new(lookahead, action));
703	}
704
705	/// Add the transaction set built up with prior calls to acttab_action() into the current action table.
706	/// Then reset the transaction set back to an empty set in preparation for a new round of acttab_action() calls.
707	///
708	/// Return the offset into the action table of the new transaction.
709	fn acttab_insert(&mut self, make_it_safe: bool) -> isize
710	{	assert!(self.a_lookahead.len() > 0);
711
712		// Make sure we have enough space to hold the expanded action table in the worst case.  The worst case occurs if the transaction set
713		// must be appended to the current action table
714		if self.n_action + self.n_symbols + 1 >= self.a_action.len()
715		{	self.a_action.resize(self.n_action + self.n_symbols + self.a_action.len() + 21, LookaheadAction::new(std::usize::MAX, std::usize::MAX));
716		}
717
718		// Scan the existing action table looking for an offset that is a duplicate of the current transaction set.  Fall out of the loop
719		// if and when the duplicate is found.
720		//
721		// i is the index in aAction[] where mnLookahead is inserted.
722		let mut found_offset = std::usize::MAX;
723		let end = if make_it_safe {self.min_lookahead} else {0};
724'l:		for i in (end .. self.n_action).rev()
725		{	if self.a_action[i].lookahead == self.min_lookahead
726			{	// All lookaheads and actions in the aLookahead[] transaction must match against the candidate aAction[i] entry.
727				if self.a_action[i].action == self.min_action
728				{	for j in 0..self.a_lookahead.len()
729					{	let k = self.a_lookahead[j].lookahead + i - self.min_lookahead;
730						if k>=self.n_action || self.a_lookahead[j].lookahead != self.a_action[k].lookahead || self.a_lookahead[j].action != self.a_action[k].action
731						{	continue 'l;
732						}
733					}
734					// No possible lookahead value that is not in the aLookahead[] transaction is allowed to match aAction[i]
735					let mut n = 0;
736					for j in 0..self.n_action
737					{	if self.a_action[j].lookahead != std::usize::MAX
738						{	if self.a_action[j].lookahead == (j + self.min_lookahead).wrapping_sub(i)
739							{	n += 1;
740							}
741						}
742					}
743					if n == self.a_lookahead.len()
744					{	found_offset = i;  // An exact match is found at offset i
745						break;
746					}
747				}
748			}
749		}
750
751		// If no existing offsets exactly match the current transaction, find an an empty offset in the aAction[] table in which we can add the aLookahead[] transaction.
752		if found_offset == std::usize::MAX
753		{	// Look for holes in the aAction[] table that fit the current aLookahead[] transaction.  Leave found_offset set to the offset of the hole.
754			// If no holes are found, found_offset is left at nAction, which means the transaction will be appended.
755			found_offset = if make_it_safe {self.min_lookahead} else {0};
756'm:			for i in found_offset .. self.a_action.len() - self.max_lookahead
757			{	if self.a_action[i].lookahead == std::usize::MAX
758				{	for j in 0 .. self.a_lookahead.len()
759					{	let k = self.a_lookahead[j].lookahead + i - self.min_lookahead;
760						if k >= self.a_action.len() || self.a_action[k].lookahead != std::usize::MAX
761						{	continue 'm;
762						}
763					}
764					for j in 0 .. self.n_action
765					{	if self.a_action[j].lookahead == (j + self.min_lookahead).wrapping_sub(i)
766						{	continue 'm;
767						}
768					}
769					found_offset = i; // Fits in empty slots
770					break;
771				}
772			}
773		}
774
775		// Insert transaction set at index found_offset
776		for j in 0 .. self.a_lookahead.len()
777		{	let k = self.a_lookahead[j].lookahead - self.min_lookahead + found_offset;
778			self.a_action[k] = self.a_lookahead[j];
779			if k >= self.n_action
780			{	self.n_action = k + 1;
781			}
782		}
783		if make_it_safe && found_offset+self.n_terminals >= self.n_action
784		{	self.n_action = found_offset+self.n_terminals+1;
785		}
786		self.a_lookahead.clear();
787
788		// Return the offset that is added to the lookahead in order to get the index into yy_action of the action
789		return found_offset as isize - self.min_lookahead as isize;
790	}
791}
792
793#[derive(Debug)]
794struct SymbolsBuilder
795{	symbols_map: HashMap<Arc<String>, Symbol>,
796	n_terminals: usize,
797	n_nonterminals: usize,
798}
799impl SymbolsBuilder
800{	pub fn new(empty: bool) -> Self
801	{	let mut this = Self
802		{	symbols_map: HashMap::new(),
803			n_terminals: 0,
804			n_nonterminals: 0,
805		};
806		if !empty
807		{	this.add(&Arc::new("$".to_string()));
808		}
809		this
810	}
811
812	/// Return a pointer to the (terminal or nonterminal) symbol "symbol_name". Create a new symbol if this is the first time "x" has been seen.
813	pub fn add(&mut self, symbol_name: &Arc<String>) -> usize
814	{	if let Some(symbol) = self.symbols_map.get(symbol_name)
815		{	symbol.index
816		}
817		else
818		{	let index = if is_terminal_name(symbol_name.as_ref()) || symbol_name.as_ref()=="$"
819			{	self.n_terminals += 1;
820				self.n_terminals - 1
821			}
822			else
823			{	self.n_nonterminals += 1;
824				self.n_nonterminals - 1
825			};
826			let symbol = Symbol::new(symbol_name, index); // need to set the name later in into_symbols()
827			self.symbols_map.insert(Arc::clone(symbol_name), symbol);
828			index
829		}
830	}
831
832	pub fn get(&self, symbol_name: &Arc<String>) -> &Symbol
833	{	&self.symbols_map[symbol_name]
834	}
835
836	pub fn get_mut(&mut self, symbol_name: &Arc<String>) -> &mut Symbol
837	{	self.symbols_map.get_mut(symbol_name).unwrap()
838	}
839
840	pub fn into_symbols(mut self, start_name: &String, nonterminal_types: HashMap<String, StringInFile>, precedence: HashMap<String, PrecedenceInFile>, rules: &mut Vec<Rule>) -> ParserResult<Symbols>
841	{	// nonterminal_types
842		for (symbol_name, symbol_type) in nonterminal_types
843		{	if let Some(symbol) = self.symbols_map.get_mut(&symbol_name)
844			{	symbol.data_type = symbol_type.string;
845			}
846			else
847			{	return Err(LemonMintError::new(&symbol_type.filename, symbol_type.n_line, format!("No such nonterminal symbol when defining symbol type: \"{}\"", symbol_name)));
848			}
849		}
850		// precedence
851		for (symbol_name, precedence) in precedence
852		{	if let Some(symbol) = self.symbols_map.get_mut(&symbol_name)
853			{	symbol.prec = precedence.precedence;
854				symbol.assoc = precedence.assoc;
855			}
856			else
857			{	return Err(LemonMintError::new(&precedence.filename, precedence.n_line, format!("No such terminal symbol \"{}\" when defining precedence", symbol_name)));
858			}
859		}
860		// convert rules
861		for rule in rules
862		{	rule.lhs_index += self.n_terminals;
863			for rhs in rule.rhs.iter_mut()
864			{	if self.symbols_map[&rhs.name].typ == SymbolType::NONTERMINAL
865				{	rhs.index += self.n_terminals;
866				}
867			}
868		}
869		// into Symbols
870		let n_symbols = self.symbols_map.len();
871		let default_symbol = self.add(&Arc::new("{default}".to_string()));
872		let default_symbol_index = default_symbol + self.n_terminals;
873		let mut start_symbol_index = std::usize::MAX;
874		let mut error_symbol_index = std::usize::MAX;
875		let mut array = Vec::with_capacity(self.symbols_map.len());
876		for (symbol_name, mut symbol) in self.symbols_map
877		{	if symbol.typ == SymbolType::NONTERMINAL
878			{	symbol.index += self.n_terminals;
879				if symbol_name.as_ref() == start_name
880				{	start_symbol_index = symbol.index;
881				}
882				else if symbol_name.as_ref() == "error"
883				{	error_symbol_index = symbol.index;
884				}
885			}
886			else if symbol.index == 0
887			{	symbol.typ = SymbolType::NONTERMINAL; // like in lemon
888			}
889			symbol.name = Arc::clone(&symbol_name);
890			array.push(symbol);
891		}
892		array.sort_by(|a, b| a.index.cmp(&b.index));
893		Ok(Symbols {array, n_symbols, n_terminals: self.n_terminals, default_symbol_index, start_symbol_index, error_symbol_index})
894	}
895}
896
897#[derive(Debug)]
898struct Symbols
899{	pub array: Vec<Symbol>, // Sorted array of all symbols
900	pub n_symbols: usize,                // Number of terminal and nonterminal symbols
901	pub n_terminals: usize,              // Number of terminal symbols
902	pub start_symbol_index: usize,
903	pub default_symbol_index: usize,
904	pub error_symbol_index: usize,
905}
906impl Symbols
907{	pub fn get_start_symbol(&self) -> &Symbol
908	{	&self.array[self.start_symbol_index]
909	}
910
911	pub fn get_error_symbol(&self) -> Option<&Symbol>
912	{	self.array.get(self.error_symbol_index)
913	}
914}
915
916#[derive(Debug)]
917struct States
918{	pub array: Vec<State>,
919	pub n_no_tail: usize, // Number of states with tail degenerate states removed
920}
921
922#[derive(Debug)]
923struct StatesBuilder;
924impl StatesBuilder
925{	/// Compute all LR(0) states for the grammar. Links are added to between some states so that the LR(1) follow sets can be computed later.
926	pub fn build(symbols: &Symbols, rules: &mut Vec<Rule>, start: &Symbol, n_terminals: usize, actions_enum: &mut i32) -> ParserResult<States>
927	{	let mut configs_basis_keys_arr = Vec::new();
928		let mut configs_basis_arr = Vec::new();
929		let mut configs_arr = Vec::new();
930		let mut configs_map = HashMap::new();
931		let mut states_map = HashMap::new();
932
933		// The basis configuration set for the first state is all rules which have the start symbol as their left-hand side
934		for n_rule in start.sym_rules_arr.iter()
935		{	rules[*n_rule].lhs_start = true;
936			Self::configlist_add(rules, &mut configs_basis_keys_arr, &mut configs_basis_arr, &mut configs_arr, &mut configs_map, n_terminals, *n_rule, 0, true).borrow_mut().fws.add(0);
937		}
938
939		// Compute the first state. All other states will be computed automatically during the computation of the first one.
940		// The returned pointer to the first state is not used.
941		Self::getstate(symbols, rules, &mut configs_basis_keys_arr, &mut configs_basis_arr, &mut configs_arr, &mut configs_map, &mut states_map, n_terminals, actions_enum)?;
942
943		let mut states = States {array: Vec::with_capacity(states_map.len()), n_no_tail: 0}; // Table of states sorted by state number
944		for (_, elem) in states_map
945		{	states.array.push(Rc::try_unwrap(elem).unwrap().into_inner());
946		}
947		states.array.sort_by(|a, b| a.n_state.cmp(&b.n_state));
948		states.n_no_tail = states.array.len();
949		Ok(states)
950	}
951
952	/// Return a pointer to a state which is described by the configuration list which has been built from calls to configlist_add.
953	fn getstate
954	(	symbols: &Symbols,
955		rules: &Vec<Rule>,
956		configs_basis_keys_arr: &mut Vec<ConfigKey>,
957		configs_basis_arr: &mut Vec<Rc<RefCell<Config>>>,
958		configs_arr: &mut Vec<Rc<RefCell<Config>>>,
959		configs_map: &mut HashMap<ConfigKey, Rc<RefCell<Config>>>,
960		states_map: &mut HashMap<Vec<ConfigKey>, Rc<RefCell<State>>>,
961		n_terminals: usize,
962		actions_enum: &mut i32,
963	) -> ParserResult<usize>
964	{	// Extract the sorted basis of the new state.  The basis was constructed by prior calls to "configlist_add(*, *, *, true)".
965		let mut basis_keys = mem::replace(configs_basis_keys_arr, Vec::new());
966		let mut basis = mem::replace(configs_basis_arr, Vec::new());
967		basis_keys.sort();
968		basis.sort();
969
970		// Find a state with the same basis
971		if let Some(found) = states_map.get(&basis_keys)
972		{	let found = found.borrow();
973			let n_state = found.n_state;
974			// A state with the same basis already exists!  Copy all the follow-set propagation links from the state under construction into the
975			// preexisting state, then return a pointer to the preexisting state
976			for (i, x) in basis.iter().enumerate()
977			{	let mut y = found.basis[i].borrow_mut();
978				if let Ok(mut x) = x.try_borrow_mut()
979				{	mem::swap(&mut x.bplp, &mut y.bplp);
980					y.bplp.reserve(x.bplp.len());
981					for config in x.bplp.iter()
982					{	y.bplp.push(Rc::clone(config));
983					}
984				}
985				else
986				{	// assume x and y are the same object
987					let len = y.bplp.len();
988					y.bplp.reserve(len);
989					for i in 0 .. len
990					{	let o = Rc::clone(&y.bplp[i]);
991						y.bplp.push(o);
992					}
993				}
994			}
995			configs_arr.clear();
996			Ok(n_state)
997		}
998		else
999		{	// This really is a new state.  Construct all the details
1000			Self::configlist_closure(symbols, rules, configs_basis_keys_arr, configs_basis_arr, configs_arr, configs_map, n_terminals)?; // Compute the configuration closure
1001			let n_state = states_map.len();
1002			let mut configurations = mem::replace(configs_arr, Vec::new());
1003			configurations.sort(); // Sort the configuration closure
1004			let stp = State::new // A new state structure
1005			(	n_state, // Every state gets a sequence number
1006				basis, // Remember the configuration basis
1007				configurations // Remember the configuration closure
1008			);
1009			let stp = Rc::new(RefCell::new(stp));
1010			states_map.insert(basis_keys, Rc::clone(&stp)); // Add to the state table
1011			let actions = Self::buildshifts(symbols, rules, configs_basis_keys_arr, configs_basis_arr, configs_arr, configs_map, states_map, n_terminals, actions_enum, &stp)?; // Recursively compute successor states
1012			stp.borrow_mut().actions = actions;
1013			Ok(n_state)
1014		}
1015	}
1016
1017	/// Construct all successor states to the given state.  A "successor" state is any state which can be reached by a shift action.
1018	fn buildshifts
1019	(	symbols: &Symbols,
1020		rules: &Vec<Rule>,
1021		configs_basis_keys_arr: &mut Vec<ConfigKey>,
1022		configs_basis_arr: &mut Vec<Rc<RefCell<Config>>>,
1023		configs_arr: &mut Vec<Rc<RefCell<Config>>>,
1024		configs_map: &mut HashMap<ConfigKey, Rc<RefCell<Config>>>,
1025		states_map: &mut HashMap<Vec<ConfigKey>, Rc<RefCell<State>>>,
1026		n_terminals: usize,
1027		actions_enum: &mut i32,
1028		stp: &Rc<RefCell<State>>
1029	) -> ParserResult<Vec<Rc<RefCell<Action>>>>
1030	{	let mut actions = Vec::new();
1031
1032		// Each configuration becomes complete after it contibutes to a successor state.  Initially, all configurations are incomplete
1033		for cfp in stp.borrow().configurations.iter()
1034		{	cfp.borrow_mut().status_is_complete = false;
1035		}
1036
1037		// Loop through all configurations of the state "stp"
1038		for (i, cfp) in stp.borrow().configurations.iter().enumerate()
1039		{	let (status_is_complete, dot, n_rule) =
1040			{	let cfp = cfp.borrow();
1041				(cfp.status_is_complete, cfp.dot, cfp.n_rule)
1042			};
1043			if !status_is_complete && dot<rules[n_rule].rhs.len() // !Already used by inner loop && !Can't shift this config
1044			{	configs_basis_keys_arr.clear();
1045				configs_basis_arr.clear();
1046				configs_arr.clear();
1047				configs_map.clear();
1048				let sp = rules[n_rule].rhs[dot].index; // Symbol following the dot in configuration "cfp"
1049
1050				// For every configuration in the state "stp" which has the symbol "sp" following its dot, add the same configuration to the basis set under
1051				// construction but with the dot shifted one symbol to the right.
1052				for bcfp in stp.borrow().configurations.iter().skip(i)
1053				{	if !bcfp.borrow().status_is_complete && bcfp.borrow().dot<rules[bcfp.borrow().n_rule].rhs.len() // !Already used && !Can't shift this one
1054					{	let bsp = rules[bcfp.borrow().n_rule].rhs[bcfp.borrow().dot].index; // Symbol following the dot in configuration "bcfp"
1055						if bsp == sp // Must be same as for "cfp"
1056						{	bcfp.borrow_mut().status_is_complete = true; // Mark this config as used
1057							let newcfg = Self::configlist_add(rules, configs_basis_keys_arr, configs_basis_arr, configs_arr, configs_map, n_terminals, bcfp.borrow().n_rule, bcfp.borrow().dot+1, true);
1058							newcfg.borrow_mut().bplp.push(Rc::clone(bcfp));
1059						}
1060					}
1061				}
1062
1063				// Get a pointer to the state described by the basis configuration set constructed in the preceding loop
1064				let n_state = Self::getstate(symbols, rules, configs_basis_keys_arr, configs_basis_arr, configs_arr, configs_map, states_map, n_terminals, actions_enum)?; // A pointer to a successor state
1065
1066				// The state "newstp" is reached from the state "stp" by a shift action on the symbol "sp"
1067				actions.insert(0, Rc::new(RefCell::new(Action::new_state(*actions_enum, sp, n_state)))); // TODO: maybe push(), not insert()
1068				*actions_enum += 1;
1069			}
1070		}
1071		Ok(actions)
1072	}
1073
1074	/// Add another configuration to the configuration list.
1075	/// dot - Index into the RHS of the rule where the dot goes
1076	fn configlist_add
1077	(	rules: &Vec<Rule>,
1078		configs_basis_keys_arr: &mut Vec<ConfigKey>,
1079		configs_basis_arr: &mut Vec<Rc<RefCell<Config>>>,
1080		configs_arr: &mut Vec<Rc<RefCell<Config>>>,
1081		configs_map: &mut HashMap<ConfigKey, Rc<RefCell<Config>>>,
1082		n_terminals: usize,
1083		n_rule: usize,
1084		dot: usize,
1085		is_basis: bool
1086	) -> Rc<RefCell<Config>>
1087	{	let key = ConfigKey {n_rule: rules[n_rule].index, dot};
1088
1089		if let Some(found) = configs_map.get(&key)
1090		{	Rc::clone(found)
1091		}
1092		else
1093		{	let cfp =  Rc::new(RefCell::new(Config::new(n_rule, dot, n_terminals+1)));
1094			configs_arr.push(Rc::clone(&cfp));
1095			let key = ConfigKey::new(&cfp.borrow());
1096			if is_basis
1097			{	configs_basis_keys_arr.push(key);
1098				configs_basis_arr.push(Rc::clone(&cfp));
1099			}
1100			configs_map.insert(key, Rc::clone(&cfp));
1101			cfp
1102		}
1103	}
1104
1105	/// Compute the closure of the configuration list
1106	fn configlist_closure
1107	(	symbols: &Symbols,
1108		rules: &Vec<Rule>,
1109		configs_basis_keys_arr: &mut Vec<ConfigKey>,
1110		configs_basis_arr: &mut Vec<Rc<RefCell<Config>>>,
1111		configs_arr: &mut Vec<Rc<RefCell<Config>>>,
1112		configs_map: &mut HashMap<ConfigKey, Rc<RefCell<Config>>>,
1113		n_terminals: usize
1114	) -> ParserResult<()>
1115	{	let mut c = 0;
1116		while c < configs_arr.len() // size of configs_arr increases during this loop
1117		{	let (rule, dot) =
1118			{	let config = configs_arr[c].borrow();
1119				(&rules[config.n_rule], config.dot)
1120			};
1121			if dot < rule.rhs.len()
1122			{	let sp = &symbols.array[rule.rhs[dot].index];
1123				if sp.typ == SymbolType::NONTERMINAL
1124				{	if sp.index!=symbols.error_symbol_index && sp.sym_rules_arr.is_empty()
1125					{	return Err(LemonMintError::new(&rule.rule_filename, rule.rule_n_line, format!("Nonterminal \"{}\" has no rules.", sp.name)));
1126					}
1127					for new_n_rule in sp.sym_rules_arr.iter()
1128					{	let newcfp = Self::configlist_add(rules, configs_basis_keys_arr, configs_basis_arr, configs_arr, configs_map, n_terminals, *new_n_rule, 0, false);
1129						let mut found = false;
1130						for i in dot+1 .. rule.rhs.len()
1131						{	let xsp = &symbols.array[rule.rhs[i].index];
1132							if xsp.typ == SymbolType::TERMINAL
1133							{	newcfp.borrow_mut().fws.add(xsp.index);
1134								found = true;
1135								break;
1136							}
1137							newcfp.borrow_mut().fws.intersect(&xsp.firstset);
1138							if !xsp.lambda
1139							{	found = true;
1140								break;
1141							}
1142						}
1143						if !found
1144						{	configs_arr[c].borrow_mut().fplp.insert(0, newcfp); // TODO: maybe push(), not insert()
1145						}
1146					}
1147				}
1148			}
1149			c += 1;
1150		}
1151		Ok(())
1152	}
1153}
1154
1155#[derive(Debug)]
1156struct StringInFile
1157{	filename: Arc<String>,
1158	n_line: usize,
1159	string: String,
1160}
1161
1162#[derive(Debug)]
1163struct PrecedenceInFile
1164{	filename: Arc<String>,
1165	n_line: usize,
1166	assoc: Associativity,
1167	precedence: i32,
1168}
1169
1170struct ArrayFormatter
1171{	i: usize,
1172	values_on_line: usize,
1173	endl: &'static str,
1174}
1175impl ArrayFormatter
1176{	pub fn new(values_on_line: usize) -> Self
1177	{	Self
1178		{	i: 0,
1179			values_on_line,
1180			endl: "\n[\t",
1181		}
1182	}
1183
1184	pub fn separ<W>(&mut self, out: &mut W) -> io::Result<()> where W: io::Write
1185	{	if self.i % self.values_on_line == 0
1186		{	write!(out, "{}/* {:5} */  ", self.endl, self.i)?;
1187			self.endl = ",\n\t";
1188		}
1189		else
1190		{	write!(out, ", ")?;
1191		}
1192		self.i += 1;
1193		Ok(())
1194	}
1195
1196	pub fn end<W>(self, out: &mut W) -> io::Result<()> where W: io::Write
1197	{	writeln!(out, "{}];", if self.i==0 {" ["} else {"\n"})
1198	}
1199}
1200
1201/// Builder class that will finally generate `LemonMint`. Call builder methods to supply parser rules and options - everything that you would normally put to Lemon's Y-grammar file.
1202/// Or you can feed the Y-file itself (it's syntax is similar to Lemon's one).
1203///
1204/// # Example
1205///
1206/// ```
1207/// use lemon_mint::LemonMintBuilder;
1208/// use std::sync::Arc;
1209///
1210/// let fake_filename = Arc::new("source.y".to_string()); // will appear in error messages
1211/// let builder = LemonMintBuilder::new().load_y(&fake_filename, "%token_type {f64}\nUnit ::= NEW_LINE.".as_bytes()).unwrap();
1212/// let lemon = builder.try_into_lemon().unwrap();
1213/// ```
1214///
1215/// Or:
1216///
1217/// ```
1218/// use lemon_mint::LemonMintBuilder;
1219/// use std::sync::Arc;
1220///
1221/// let fake_filename = Arc::new("source.y".to_string()); // will appear in error messages
1222/// let builder = LemonMintBuilder::new()
1223/// 	.set_token_type("f64".to_string()).unwrap()
1224/// 	.add_rule(&fake_filename, 1, "Unit".to_string(), "NEW_LINE", "".to_string()).unwrap();
1225/// let lemon = builder.try_into_lemon().unwrap();
1226/// ```
1227#[derive(Debug)]
1228pub struct LemonMintBuilder
1229{	rules: Vec<Rule>,                  // All rules
1230	token_type: String,                // Type of terminal symbols in the parser stack
1231	vartype: String,                   // The default type of non-terminal symbols
1232	start_name: String,                // Name of the start symbol for the grammar
1233	with_trace: bool,
1234	trace_prompt: String,              // Prompt to preface each trace message, if with_trace is true
1235	extracode: String,                 // Code appended to the generated file
1236	n_conflicts: usize,                // Number of parsing conflicts
1237	n_action_table_entries: usize,     // Number of entries in the yy_action[] table
1238	tables_size: usize,                // Total table size of all tables in bytes
1239	has_fallback: bool,                // True if any %fallback is seen in the grammar
1240	symbols_builder: SymbolsBuilder,
1241	prec_counter: i32,
1242	actions_enum: i32,
1243	nonterminal_types: HashMap<String, StringInFile>,
1244	precedence: HashMap<String, PrecedenceInFile>,
1245	extra_argument_type: String,
1246	min_shift_reduce: usize,
1247	error_action: usize,
1248	accept_action: usize,
1249	no_action: usize,
1250	min_reduce: usize,
1251	max_action: usize,
1252	no_compress: bool,                 // Don't compress the action table
1253	no_resort: bool,                   // Do not sort or renumber states
1254}
1255impl LemonMintBuilder
1256{	/// Creates new builder
1257	pub fn new() -> Self
1258	{	Self
1259		{	rules: Vec::with_capacity(64),
1260			token_type: String::new(),
1261			vartype: String::new(),
1262			start_name: String::new(),
1263			with_trace: false,
1264			trace_prompt: String::new(),
1265			extracode: String::new(),
1266			n_conflicts: 0,
1267			n_action_table_entries: 0,
1268			tables_size: 0,
1269			has_fallback: false,
1270			symbols_builder: SymbolsBuilder::new(false),
1271			prec_counter: 1,
1272			actions_enum: 0,
1273			nonterminal_types: HashMap::new(),
1274			precedence: HashMap::new(),
1275			extra_argument_type: String::new(),
1276			min_shift_reduce: 0,
1277			error_action: 0,
1278			accept_action: 0,
1279			no_action: 0,
1280			min_reduce: 0,
1281			max_action: 0,
1282			no_compress: false,
1283			no_resort: false,
1284		}
1285	}
1286
1287	/// Find a precedence symbol of every rule in the grammar.
1288	///
1289	/// Those rules which have a precedence symbol coded in the input grammar using the `"[symbol]"` construct will already have the
1290	/// rule->precsym field filled.  Other rules take as their precedence symbol the first RHS symbol with a defined precedence.  If there
1291	/// are not RHS symbols with a defined precedence, the precedence symbol field is left blank.
1292	fn find_rule_precedences(symbols: &mut Symbols, rules: &mut Vec<Rule>)
1293	{	for rule in rules.iter_mut()
1294    	{	if rule.precsym_index == std::usize::MAX
1295			{	for sp in &rule.rhs
1296				{	if symbols.array[sp.index].prec >= 0
1297					{	rule.precsym_index = sp.index;
1298						break;
1299					}
1300				}
1301			}
1302		}
1303	}
1304
1305	/// Find all nonterminals which will generate the empty string.  Then go back and compute the first sets of every nonterminal.
1306	/// The first set is the set of all terminal symbols which can begin a string generated by that nonterminal.
1307	fn find_first_sets(&self, symbols: &mut Symbols, rules: &mut Vec<Rule>)
1308	{	for (i, symbol) in symbols.array[0 .. symbols.n_symbols].iter_mut().enumerate()
1309		{	symbol.lambda = false;
1310			if i >= symbols.n_terminals
1311			{	symbol.firstset.set_size(symbols.n_terminals + 1);
1312			}
1313		}
1314
1315		// First compute all lambdas
1316		let mut progress = true;
1317		while progress
1318		{	progress = false;
1319'l:			for rule in rules.iter()
1320			{	let rule = rule;
1321				if !symbols.array[rule.lhs_index].lambda
1322				{	for sp in &rule.rhs
1323					{	let sp = &symbols.array[sp.index];
1324						assert!(sp.typ==SymbolType::NONTERMINAL || !sp.lambda);
1325						if !sp.lambda
1326						{	continue 'l;
1327						}
1328					}
1329					symbols.array[rule.lhs_index].lambda = true;
1330					progress = true;
1331				}
1332			}
1333		}
1334
1335		// Now compute all first sets
1336		progress = true;
1337		while progress
1338		{	progress = false;
1339			for rule in rules.iter()
1340			{	for rhs in &rule.rhs
1341				{	if symbols.array[rhs.index].typ == SymbolType::TERMINAL
1342					{	if symbols.array[rule.lhs_index].firstset.add(rhs.index)
1343						{	progress = true;
1344						}
1345						break;
1346					}
1347					else if rule.lhs_index == rhs.index
1348					{	if !symbols.array[rule.lhs_index].lambda
1349						{	break;
1350						}
1351					}
1352					else
1353					{	let set = mem::replace(&mut symbols.array[rhs.index].firstset, Set::new(0));
1354						if symbols.array[rule.lhs_index].firstset.intersect(&set)
1355						{	progress = true;
1356						}
1357						symbols.array[rhs.index].firstset = set;
1358						if !symbols.array[rhs.index].lambda
1359						{	break;
1360						}
1361					}
1362				}
1363			}
1364		}
1365	}
1366
1367	/// Construct the propagation links
1368	fn find_links(states: &States)
1369    {	// Housekeeping detail:
1370		// Add to every propagate link a pointer back to the state to which the link is attached.
1371		for stp in states.array.iter()
1372		{	for cfp in stp.configurations.iter()
1373			{	cfp.borrow_mut().n_state = stp.n_state;
1374			}
1375		}
1376
1377		// Convert all backlinks into forward links.
1378    	// Only the forward links are used in the follow-set computation.
1379    	for stp in states.array.iter()
1380    	{	for cfp in stp.configurations.iter()
1381    		{	for plp in cfp.borrow().bplp.iter()
1382    			{	plp.borrow_mut().fplp.insert(0, Rc::clone(&cfp)); // TODO: maybe push(), not insert()
1383    			}
1384    		}
1385    	}
1386    }
1387
1388	/// Compute all followsets.
1389    ///
1390    /// A followset is the set of all symbols which can come immediately after a configuration.
1391    fn find_follow_sets(states: &States)
1392    {	for stp in states.array.iter()
1393    	{	for cfp in stp.configurations.iter()
1394    		{	cfp.borrow_mut().status_is_complete = false;
1395    		}
1396    	}
1397
1398    	let mut progress = true;
1399		while progress
1400		{	progress = false;
1401    		for stp in states.array.iter()
1402    		{	for cfp in stp.configurations.iter()
1403    			{	if !cfp.borrow().status_is_complete
1404					{	for plp in cfp.borrow().fplp.iter()
1405						{	let mut plp = plp.borrow_mut();
1406							if plp.fws.intersect(&cfp.borrow().fws) // if changed
1407							{	plp.status_is_complete = false;
1408								progress = true;
1409							}
1410						}
1411						cfp.borrow_mut().status_is_complete = true;
1412					}
1413    			}
1414    		}
1415    	}
1416    }
1417
1418	/// Resolve a conflict between the two given actions.  If the conflict can't be resolved, return non-zero.
1419    ///
1420    /// NO LONGER TRUE:
1421    ///   To resolve a conflict, first look to see if either action is on an error rule.  In that case, take the action which
1422    ///   is not associated with the error rule.  If neither or both actions are associated with an error rule, then try to
1423    ///   use precedence to resolve the conflict.
1424    ///
1425    /// If either action is a SHIFT, then it must be apx.  This function won't work if apx->type==REDUCE and apy->type==SHIFT.
1426    fn resolve_conflict(symbols: &Symbols, rules: &mut Vec<Rule>, apx: &Rc<RefCell<Action>>, apy: &Rc<RefCell<Action>>) -> usize
1427	{	let mut errcnt = 0;
1428		let mut apx = apx.borrow_mut();
1429		let mut apy = apy.borrow_mut();
1430		assert_eq!(apx.symbol_index, apy.symbol_index);  // Otherwise there would be no conflict
1431		let mut apx_typ = apx.typ;
1432		let mut apy_typ = apy.typ;
1433		if apx_typ==ActionType::Shift && apy_typ==ActionType::Shift
1434		{	apy_typ = ActionType::SsConflict;
1435			errcnt += 1;
1436		}
1437		if apx_typ==ActionType::Shift && apy_typ==ActionType::Reduce
1438		{	let spx = &symbols.array[apx.symbol_index];
1439			if let StateOrRule::Rule(n_rule) = apy.x
1440			{	let spy = rules[n_rule].precsym_index;
1441				if spy != std::usize::MAX
1442				{	let spy = &symbols.array[spy];
1443					if spx.prec<0 || spy.prec<0
1444					{	// Not enough precedence information.
1445						apy_typ = ActionType::SrConflict;
1446						errcnt += 1;
1447					}
1448					else if spx.prec > spy.prec    // higher precedence wins
1449					{	apy_typ = ActionType::RdResolved;
1450					}
1451					else if spx.prec < spy.prec
1452					{	apx_typ = ActionType::ShResolved;
1453					}
1454					else if spx.prec==spy.prec && spx.assoc== Associativity::RIGHT // Use operator
1455					{	apy_typ = ActionType::RdResolved;                          // associativity
1456					}
1457					else if spx.prec==spy.prec && spx.assoc== Associativity::LEFT  // to break tie
1458					{	apx_typ = ActionType::ShResolved;
1459					}
1460					else
1461					{	assert!(spx.prec==spy.prec && spx.assoc== Associativity::NONASSOC);
1462						apy_typ = ActionType::Error;
1463					}
1464				}
1465				else
1466				{	// Not enough precedence information.
1467					apy_typ = ActionType::SrConflict;
1468					errcnt += 1;
1469				}
1470			}
1471		}
1472		else if apx_typ==ActionType::Reduce && apy_typ==ActionType::Reduce
1473		{	if let StateOrRule::Rule(n_rule_x) = apx.x
1474			{	if let StateOrRule::Rule(n_rule_y) = apy.x
1475				{	let spx = rules[n_rule_x].precsym_index;
1476					let spy = rules[n_rule_y].precsym_index;
1477					if spx != std::usize::MAX
1478					{	if spy != std::usize::MAX
1479						{	let spx = &symbols.array[spx];
1480							let spy = &symbols.array[spy];
1481							if spx.prec<0 || spy.prec<0 || spx.prec==spy.prec
1482							{	apy_typ = ActionType::RrConflict;
1483								errcnt += 1;
1484							}
1485							else if spx.prec > spy.prec
1486							{	apy_typ = ActionType::RdResolved;
1487							}
1488							else if spx.prec < spy.prec
1489							{	apx_typ = ActionType::RdResolved;
1490							}
1491						}
1492						else
1493						{	apy_typ = ActionType::RrConflict;
1494							errcnt += 1;
1495						}
1496					}
1497					else
1498					{	apy_typ = ActionType::RrConflict;
1499						errcnt += 1;
1500					}
1501				}
1502			}
1503		}
1504		else
1505		{	assert!
1506			(	apx_typ == ActionType::ShResolved ||
1507				apx_typ == ActionType::RdResolved ||
1508				apx_typ == ActionType::SsConflict ||
1509				apx_typ == ActionType::SrConflict ||
1510				apx_typ == ActionType::RrConflict ||
1511				apy_typ == ActionType::ShResolved ||
1512				apy_typ == ActionType::RdResolved ||
1513				apy_typ == ActionType::SsConflict ||
1514				apy_typ == ActionType::SrConflict ||
1515				apy_typ == ActionType::RrConflict
1516			);
1517			// The REDUCE/SHIFT case cannot happen because SHIFTs come before REDUCEs on the list.  If we reach this point it must be because
1518			// the parser conflict had already been resolved.
1519		}
1520		apx.typ = apx_typ;
1521		apy.typ = apy_typ;
1522		errcnt
1523    }
1524
1525	/// Compute the reduce actions, and resolve conflicts.
1526    fn find_actions(&mut self, symbols: &Symbols, rules: &mut Vec<Rule>, states: &mut States) -> ParserResult<()>
1527    {	// Add all of the reduce actions
1528    	// A reduce action is added for each element of the followset of a configuration which has its dot at the extreme right.
1529    	for stp in states.array.iter_mut()   // Loop over all states
1530    	{	for cfp in stp.configurations.iter()  // Loop over all configurations
1531    		{	if cfp.borrow().dot == rules[cfp.borrow().n_rule].rhs.len()  // Is dot at extreme right?
1532    			{	for (j, symbol) in symbols.array.iter().take(symbols.n_terminals).enumerate()
1533    				{	if cfp.borrow().fws.contains(j)
1534    					{	// Add a reduce action to the state "stp" which will reduce by the rule "cfp->rule" if the lookahead symbol is "symbols[j]"
1535    						stp.actions.push(Rc::new(RefCell::new(Action::new_rule(self.actions_enum, symbol.index, ActionType::Reduce, cfp.borrow().n_rule))));
1536							self.actions_enum += 1;
1537    					}
1538    				}
1539    			}
1540    		}
1541    	}
1542
1543    	// Add the accepting token
1544    	// Add to the first state (which is always the starting state of the finite state machine) an action to ACCEPT if the lookahead is the start nonterminal.
1545    	states.array[0].actions.push(Rc::new(RefCell::new(Action::new_empty_rule(self.actions_enum, symbols.start_symbol_index, ActionType::Accept))));
1546		self.actions_enum += 1;
1547
1548    	// Resolve conflicts
1549    	for stp in states.array.iter_mut()
1550    	{	if stp.actions.len() != 0
1551    		{	stp.actions.sort();
1552    			for action in stp.actions.windows(2)
1553				{	if action[0].borrow().symbol_index == action[1].borrow().symbol_index
1554    				{	// The two actions "action[0]" and "action[1]" have the same lookahead.
1555    					// Figure out which one should be used
1556    					self.n_conflicts += Self::resolve_conflict(symbols, rules, &action[0], &action[1]);
1557    				}
1558				}
1559    		}
1560    	}
1561
1562    	// Report an error for each rule that can never be reduced.
1563    	for stp in states.array.iter_mut()
1564    	{	for action in stp.actions.iter()
1565    		{	if action.borrow().typ == ActionType::Reduce
1566				{	if let StateOrRule::Rule(n_rule) = action.borrow().x
1567					{	rules[n_rule].can_reduce = true;
1568					}
1569				}
1570    		}
1571    	}
1572    	for rule in rules.iter()
1573		{	if !rule.can_reduce
1574			{	return Err(LemonMintError::new(&rule.rule_filename, rule.rule_n_line, "This rule can not be reduced.\n".to_string()));
1575			}
1576		}
1577		Ok(())
1578    }
1579
1580	fn get_filename_of_first_rule(rules: &Vec<Rule>) -> Arc<String>
1581	{	if let Some(rule) = rules.iter().next()
1582		{	return Arc::clone(&rule.rule_filename);
1583		}
1584		Arc::new("".to_string())
1585	}
1586
1587	/// Reduce the size of the action tables, if possible, by making use of defaults.
1588	///
1589	/// In this version, we take the most frequent REDUCE action and make it the default.
1590	fn compress_tables(&self, symbols: &Symbols, rules: &Vec<Rule>, states: &mut States, default_symbol_index: usize)
1591	{	for state in states.array.iter_mut()
1592		{	let mut n_best = 0;
1593			let mut r_best = std::usize::MAX;
1594
1595			let mut it = state.actions.iter();
1596			while let Some(action) = it.next()
1597			{	if action.borrow().typ == ActionType::Reduce
1598				{	if let StateOrRule::Rule(n_rule) = action.borrow().x
1599					{	let rule = &rules[n_rule];
1600						if !rule.lhs_start && n_rule != r_best
1601						{	let mut n = 1;
1602							let mut it2 = it.clone();
1603							while let Some(ap2) = it2.next()
1604							{	if ap2.borrow().typ == ActionType::Reduce
1605								{	if let StateOrRule::Rule(n_rule_2) = ap2.borrow().x
1606									{	if n_rule_2 != r_best && n_rule_2 == n_rule
1607										{	n += 1;
1608										}
1609									}
1610								}
1611							}
1612							if n > n_best
1613							{	n_best = n;
1614								r_best = n_rule;
1615							}
1616						}
1617					}
1618				}
1619			}
1620
1621			// Do not make a default if the number of rules to default is not at least 1
1622			if n_best < 1
1623			{	continue;
1624			}
1625
1626			// Combine matching REDUCE actions into a single default
1627			let mut found = false;
1628			for action in state.actions.iter()
1629			{	let mut action =  action.borrow_mut();
1630				if action.typ == ActionType::Reduce
1631				{	if let StateOrRule::Rule(n_rule) = action.x
1632					{	if rules[n_rule].index == r_best
1633						{	if !found
1634							{	action.symbol_index = default_symbol_index;
1635								found = true;
1636							}
1637							else
1638							{	action.typ = ActionType::NotUsed;
1639							}
1640						}
1641					}
1642				}
1643			}
1644			assert!(found);
1645			state.actions.sort();
1646
1647			found = false;
1648			for action in state.actions.iter()
1649			{	let action = action.borrow();
1650				if action.typ==ActionType::Shift || action.typ==ActionType::Reduce && match action.x {StateOrRule::Rule(n_rule) => rules[n_rule].index != r_best, _ => false}
1651				{	found = true;
1652					break;
1653				}
1654			}
1655			if !found
1656			{	state.auto_reduce = true;
1657				state.default_reduce_rule = r_best;
1658			}
1659		}
1660
1661		// Make a second pass over all states and actions.  Convert every action that is a SHIFT to an autoReduce state into a SHIFTREDUCE action.
1662		for stp in states.array.iter()
1663		{	for action in stp.actions.iter()
1664			{	let mut action = action.borrow_mut();
1665				if action.typ == ActionType::Shift
1666				{	if let StateOrRule::State(next_n_state) = action.x
1667					{	let next_state = &states.array[next_n_state];
1668						if next_state.auto_reduce && next_state.default_reduce_rule!=std::usize::MAX
1669						{	action.typ = ActionType::ShiftReduce;
1670							action.x = StateOrRule::Rule(next_state.default_reduce_rule);
1671						}
1672					}
1673				}
1674			}
1675		}
1676
1677		// If a SHIFTREDUCE action specifies a rule that has a single RHS term (meaning that the SHIFTREDUCE will land back in the state where it
1678		// started) and if there is no C-code associated with the reduce action, then we can go ahead and convert the action to be the same as the
1679		// action for the RHS of the rule.
1680		for stp in states.array.iter()
1681		{	for action in stp.actions.iter()
1682			{	let mut done = false;
1683				while !done
1684				{	done = true;
1685					let mut ap2 = None;
1686					{	let action = action.borrow();
1687						if action.typ == ActionType::ShiftReduce
1688						{	if let StateOrRule::Rule(n_rule) = action.x
1689							{	let rp = &rules[n_rule];
1690								if rp.code.is_empty() && rp.rhs.len()==1
1691								{	// Only apply this optimization to non-terminals.  It would be OK to apply it to terminal symbols too, but that makes the parser tables larger.
1692									if action.symbol_index >= symbols.n_terminals
1693									{	// If we reach this point, it means the optimization can be applied
1694										ap2 = stp.actions.iter().find
1695										(	|a|
1696											{	let a = a.borrow();
1697												a.id!= action.id && a.symbol_index==rp.lhs_index
1698											}
1699										);
1700										assert!(ap2.is_some());
1701										done = false;
1702									}
1703								}
1704							}
1705						}
1706					}
1707					if let Some(ap2) = ap2
1708					{	let mut action = action.borrow_mut();
1709						let ap2 = ap2.borrow();
1710						action.symbol_index_opt = ap2.symbol_index;
1711						action.typ = ap2.typ;
1712						action.x = ap2.x;
1713					}
1714				}
1715			}
1716		}
1717	}
1718
1719	/// Given an action, compute the integer value for that action which is to be put in the action table of the generated machine.
1720	/// Return negative if no action should be generated.
1721	fn compute_action(&self, symbols: &Symbols, action: &Rc<RefCell<Action>>) -> usize
1722	{	let action = action.borrow();
1723		match action.typ
1724		{	ActionType::Shift =>
1725			{	match action.x
1726				{	StateOrRule::State(n_state) => n_state,
1727					_ => std::usize::MAX
1728				}
1729			}
1730			ActionType::ShiftReduce =>
1731			{	// Since a SHIFT is inherient after a prior REDUCE, convert any SHIFTREDUCE action with a nonterminal on the LHS into a simple REDUCE action:
1732				match action.x
1733				{	StateOrRule::Rule(n_rule) =>
1734					{	if action.symbol_index >= symbols.n_terminals
1735						{	self.min_reduce + n_rule
1736						}
1737						else
1738						{	self.min_shift_reduce + n_rule
1739						}
1740					},
1741					_ => std::usize::MAX
1742				}
1743			}
1744			ActionType::Reduce =>
1745			{	match action.x
1746				{	StateOrRule::Rule(n_rule) => self.min_reduce + n_rule,
1747					_ => std::usize::MAX
1748				}
1749			}
1750			ActionType::Error =>
1751			{	self.error_action
1752			}
1753			ActionType::Accept =>
1754			{	self.accept_action
1755			}
1756			_ => std::usize::MAX
1757		}
1758	}
1759
1760	/// Renumber and resort states so that states with fewer choices occur at the end.  Except, keep state 0 as the first state.
1761	fn resort_states(&mut self, symbols: &Symbols, states: &mut States)
1762	{	let sorted_len = states.array.len();
1763		for stp in states.array.iter_mut()
1764		{	stp.n_token_act = 0;
1765			stp.n_nt_act = 0;
1766			stp.default_reduce_action = std::usize::MAX; // Init dflt action to "syntax error"
1767			stp.token_offset = std::isize::MIN;
1768			stp.nt_offset = std::isize::MIN;
1769			for action in stp.actions.iter()
1770			{	let n_action = self.compute_action(symbols, action);
1771				if n_action != std::usize::MAX
1772				{	let action = action.borrow();
1773					if action.symbol_index < symbols.n_terminals
1774					{	stp.n_token_act += 1;
1775					}
1776					else if action.symbol_index < symbols.n_symbols
1777					{	stp.n_nt_act += 1;
1778					}
1779					else
1780					{	assert!(!stp.auto_reduce || action.x == StateOrRule::Rule(stp.default_reduce_rule));
1781						stp.default_reduce_action = n_action;
1782					}
1783				}
1784			}
1785		}
1786
1787		// Compare two states for sorting purposes.  The smaller state is the one with the most non-terminal actions.
1788		// If they have the same number of non-terminal actions, then the smaller is the one with the most token actions.
1789		if sorted_len > 2
1790		{	states.array[1 ..].sort_by
1791			(	|a, b|
1792				{	let mut res = b.n_nt_act.cmp(&a.n_nt_act);
1793					if res == Ordering::Equal
1794					{	res = b.n_token_act.cmp(&a.n_token_act);
1795						if res == Ordering::Equal
1796						{	res = b.n_state.cmp(&a.n_state);
1797						}
1798					}
1799					res
1800				}
1801			);
1802		}
1803
1804		// update also in actions and configurations
1805		let mut map = Vec::new();
1806		map.resize(states.array.len(), 0);
1807		for (i, stp) in states.array.iter().enumerate()
1808		{	map[stp.n_state] = i;
1809		}
1810		for stp in states.array.iter()
1811		{	for action in stp.actions.iter()
1812			{	if let StateOrRule::State(ref mut state) = action.borrow_mut().x
1813				{	*state = map[*state];
1814				}
1815			}
1816			for configuration in stp.configurations.iter()
1817			{	let mut configuration = configuration.borrow_mut();
1818				configuration.n_state = map[configuration.n_state];
1819			}
1820		}
1821
1822		// update self
1823		for (new_n_state, stp) in states.array.iter_mut().enumerate()
1824		{	stp.n_state = new_n_state;
1825		}
1826
1827		while states.n_no_tail>1 && states.array[states.n_no_tail-1].auto_reduce
1828		{	states.n_no_tail -= 1;
1829		}
1830	}
1831
1832	/// Return the name of a C datatype able to represent values between lwr and upr, inclusive.
1833	fn minimum_size_type(lower: isize, upper: isize) -> isize
1834	{	if lower >= 0
1835		{	if upper <= 255
1836			{	1
1837			}
1838			else if upper < 65535
1839			{	2
1840			}
1841			else
1842			{	4
1843			}
1844		}
1845		else
1846		{	if lower>=-127 && upper<=127
1847			{	-1
1848			}
1849			else if lower>=-32767 && upper<32767
1850			{	-2
1851			}
1852			else
1853			{	-4
1854			}
1855		}
1856	}
1857
1858	/// zCode is a string that is the action associated with a rule.  Expand the symbols in this string so that the refer to elements of the parser stack.
1859	fn translate_code(&self, rule: &mut Rule) -> ParserResult<()>
1860	{	let mut used = Vec::new();   // True for each RHS element which is used
1861		used.resize(rule.rhs.len(), false);
1862
1863		let mut it = rule.code.chars();
1864		let mut it_prev = it.clone();
1865
1866		while let Some(cp) = it.next()
1867		{	if cp.is_ascii_alphabetic()
1868			{	let ident: String = it_prev.take_while(|c| c.is_ascii_alphanumeric() || *c=='_').collect();
1869				if ident.len() > 1
1870				{	it.nth(ident.chars().count() - 2).unwrap();
1871				}
1872				for (i, rhs) in rule.rhs.iter().enumerate()
1873				{	if rhs.alias == ident
1874					{	used[i] = true;
1875						break;
1876					}
1877				}
1878			}
1879			it_prev = it.clone();
1880		}
1881
1882		// Generate warnings for RHS symbols which aliases are not used in the reduce code
1883		for (i, rhs) in rule.rhs.iter().enumerate()
1884		{	if !rhs.alias.is_empty() && !used[i]
1885			{	return Err
1886				(	LemonMintError::new
1887					(	&rule.rule_filename,
1888						rule.rule_n_line,
1889						format!("Label {} for \"{}({})\" is never used.", rhs.alias, rhs.name, rhs.alias)
1890					)
1891				);
1892			}
1893		}
1894
1895		Ok(())
1896	}
1897
1898	/*
1899	** Print the definition of the union used for the parser's data stack.
1900	** This union contains fields for every possible data type for tokens
1901	** and nonterminals.  In the process of computing and printing this
1902	** union, also set the ".dtnum" field of every terminal and nonterminal
1903	** symbol.
1904	*/
1905	fn get_minor_type(&self, symbols: &mut Symbols) -> Vec<(String, String)>
1906	{	// Allocate and initialize types[] and allocate stddt[]
1907		let arraysize = symbols.n_symbols * 2; // Size of the "types" array
1908		let mut types = Vec::new(); // A hash table of datatypes
1909		types.resize(arraysize, String::new());
1910
1911		// Build a hash table of datatypes. The ".dtnum" field of each symbol is filled in with the hash index plus 1.  A ".dtnum" value of 0 is
1912		// used for terminal symbols.  If there is no %default_type defined then 0 is also used as the .dtnum value for nonterminals which do not specify
1913		// a datatype using the %type directive.
1914'l:		for (i, sp) in symbols.array[0 .. symbols.n_symbols].iter_mut().enumerate()
1915		{	if i == symbols.error_symbol_index
1916			{	sp.dtnum = arraysize+1;
1917				continue;
1918			}
1919			if sp.typ==SymbolType::TERMINAL || (sp.data_type.is_empty() && self.vartype.is_empty())
1920			{	sp.dtnum = 0;
1921				continue;
1922			}
1923			let stddt = if !sp.data_type.is_empty()
1924			{	&sp.data_type
1925			}
1926			else
1927			{	&self.vartype
1928			};
1929			if !self.token_type.is_empty() && &self.token_type == stddt
1930			{	sp.dtnum = 0;
1931				continue;
1932			}
1933			let mut hash = DefaultHasher::new();
1934			stddt.hash(&mut hash);
1935			let mut hash = hash.finish() as usize % arraysize;
1936			while !types[hash].is_empty()
1937			{	if &types[hash] == stddt
1938				{	sp.dtnum = hash + 1;
1939					continue 'l;
1940				}
1941				hash += 1;
1942				if hash >= arraysize
1943				{	hash = 0;
1944				}
1945			}
1946			sp.dtnum = hash + 1;
1947			types[hash] = stddt.to_string(); // TODO: no to_string()
1948		}
1949
1950		// Print out the definition of TokenValue and MinorType
1951		let mut minor_type = Vec::with_capacity(arraysize+3);
1952		minor_type.push(("None".to_string(), "".to_string()));
1953		minor_type.push(("Symbol0".to_string(), "TokenValue".to_string()));
1954		let mut i = 1;
1955		for name in types
1956		{	if !name.is_empty()
1957			{	minor_type.push((format!("Symbol{}", i), name));
1958			}
1959			i += 1;
1960		}
1961		if let Some(symbol) = symbols.get_error_symbol()
1962		{	minor_type.push((format!("Symbol{}", symbol.dtnum), "i32".to_string()));
1963		}
1964
1965		// Done
1966		minor_type
1967	}
1968
1969	fn init_acttab(&mut self, symbols: &Symbols, rules: &mut Vec<Rule>, states: &mut States) -> ActTab
1970	{	let mut acttab = ActTab::new(symbols.n_terminals, symbols.n_symbols);
1971
1972		// Compute the actions on all states and count them up
1973		let mut ax = Vec::with_capacity(states.n_no_tail*2);
1974		for stp in states.array[0 .. states.n_no_tail].iter()
1975		{	ax.push(AxSet::new(stp.n_state, true, stp.n_token_act, ax.len()));
1976			ax.push(AxSet::new(stp.n_state, false, stp.n_nt_act, ax.len()));
1977		}
1978		ax.sort();
1979
1980		let mut min_token_offset = 0;
1981		let mut max_token_offset = 0;
1982		let mut min_nt_offset = 0;
1983		let mut max_nt_offset = 0;
1984
1985		// Compute the action table.  In order to try to keep the size of the action table to a minimum, the heuristic of placing the largest action sets first is used.
1986		for ax_i in ax.iter()
1987		{	if ax_i.n_action == 0
1988			{	break;
1989			}
1990			let stp = &mut states.array[ax_i.n_state];
1991			if ax_i.is_tkn
1992			{	for action in stp.actions.iter()
1993				{	if action.borrow().symbol_index < symbols.n_terminals
1994					{	let n_action = self.compute_action(symbols, action);
1995						if n_action != std::usize::MAX
1996						{	acttab.acttab_action(action.borrow().symbol_index, n_action);
1997						}
1998					}
1999				}
2000				stp.token_offset = acttab.acttab_insert(true);
2001				if stp.token_offset < min_token_offset
2002				{	min_token_offset = stp.token_offset;
2003				}
2004				if stp.token_offset > max_token_offset
2005				{	max_token_offset = stp.token_offset;
2006				}
2007			}
2008			else
2009			{	for action in stp.actions.iter()
2010				{	if action.borrow().symbol_index >= symbols.n_terminals && action.borrow().symbol_index != symbols.n_symbols
2011					{	let n_action = self.compute_action(symbols, action);
2012						if n_action != std::usize::MAX
2013						{	acttab.acttab_action(action.borrow().symbol_index, n_action);
2014						}
2015					}
2016				}
2017				stp.nt_offset = acttab.acttab_insert(false);
2018				if stp.nt_offset < min_nt_offset
2019				{	min_nt_offset = stp.nt_offset;
2020				}
2021				if stp.nt_offset > max_nt_offset
2022				{	max_nt_offset = stp.nt_offset;
2023				}
2024			}
2025		}
2026
2027		// Mark rules that are actually used for reduce actions after all optimizations have been applied
2028		for rule in rules.iter_mut()
2029		{	rule.does_reduce = false;
2030		}
2031		for state in states.array[0 .. states.n_no_tail].iter()
2032		{	for action in state.actions.iter()
2033			{	let action = action.borrow_mut();
2034				if action.typ==ActionType::Reduce || action.typ==ActionType::ShiftReduce
2035				{	if let StateOrRule::Rule(n_rule) = action.x
2036					{	rules[n_rule].does_reduce = true;
2037					}
2038				}
2039			}
2040		}
2041
2042		let mut n_fallbacks = 0;
2043		if self.has_fallback
2044		{	n_fallbacks = symbols.n_terminals - 1;
2045			while n_fallbacks>0 && symbols.array[n_fallbacks].fallback_index==std::usize::MAX
2046			{	n_fallbacks -= 1;
2047			}
2048			n_fallbacks += 1;
2049		}
2050		self.has_fallback = n_fallbacks != 0;
2051
2052		let mut n_shift_offset = states.n_no_tail;
2053		while n_shift_offset >0 && states.array[n_shift_offset -1].token_offset == std::isize::MIN
2054		{	n_shift_offset -= 1;
2055		}
2056
2057		let mut reduce_count = states.n_no_tail;
2058		while reduce_count>0 && states.array[reduce_count-1].nt_offset == std::isize::MIN
2059		{	reduce_count -= 1;
2060		}
2061
2062		acttab.min_token_offset = min_token_offset;
2063		acttab.max_token_offset = max_token_offset;
2064		acttab.min_nt_offset = min_nt_offset;
2065		acttab.max_nt_offset = max_nt_offset;
2066		acttab.n_fallbacks = n_fallbacks;
2067		acttab.n_shift_offset = n_shift_offset;
2068		acttab.reduce_count = reduce_count;
2069
2070		acttab
2071	}
2072
2073	/// Generate source code for the parser
2074	fn get_lemon(mut self, mut symbols: Symbols, mut rules: Vec<Rule>, states: States, acttab: ActTab) -> ParserResult<LemonMint>
2075	{	// Generate types
2076		let sz_code_type = Self::minimum_size_type(0, symbols.n_symbols as isize+1);
2077		let sz_action_type =  Self::minimum_size_type(0, (states.array.len()+rules.len()+5) as isize);
2078		let sz_shift_offset_type =  Self::minimum_size_type(acttab.min_token_offset-1, acttab.max_token_offset);
2079		let sz_reduce_offset_type =  Self::minimum_size_type(acttab.min_nt_offset-1, acttab.max_nt_offset);
2080
2081		// Generate token constants
2082		let mut token = Vec::with_capacity(symbols.n_terminals);
2083		for symbol in symbols.array[1 .. symbols.n_terminals].iter()
2084		{	token.push(Arc::clone(&symbol.name));
2085		}
2086
2087		// Generate the table of rule information
2088		// Note: This code depends on the fact that rules are number sequentually beginning with 0.
2089		self.tables_size += rules.len() * sz_code_type.abs() as usize;
2090
2091		// Generate the action table and its associates:
2092		//
2093		//  yy_action[]        A single table containing all actions.
2094		//  yy_lookahead[]     A table containing the lookahead for each entry in
2095		//                     yy_action.  Used to detect hash collisions.
2096		//  SHIFT_OFFSET[]    For each state, the offset into yy_action for
2097		//                     shifting terminals.
2098		//  REDUCE_OFFSET[]   For each state, the offset into yy_action for
2099		//                     shifting non-terminals after a reduce.
2100		//  DEFAULT[]       Default action for each state.
2101
2102		// Output the LOOKAHEAD_AND_ACTION table
2103		self.n_action_table_entries = acttab.get_n_actions();
2104		let mut n = acttab.get_n_lookahead();
2105		let n_lookahead = std::cmp::max(n, symbols.n_terminals + self.n_action_table_entries);
2106		let mut lookahead_and_action = Vec::with_capacity(n_lookahead);
2107		for (i, LookaheadAction {lookahead, action}) in acttab.iter().enumerate()
2108		{	let lookahead = if *lookahead == std::usize::MAX {symbols.n_symbols} else {*lookahead};
2109			let action = if i >= self.n_action_table_entries {0} else if *action == std::usize::MAX {self.no_action} else {*action};
2110			lookahead_and_action.push((lookahead, action));
2111		}
2112		// Add extra entries to the end of the yy_lookahead[] table so that yy_shift_ofst[]+iToken will always be a valid index into the array,
2113		// even for the largest possible value of yy_shift_ofst[] and iToken.
2114		while n < n_lookahead
2115		{	lookahead_and_action.push((symbols.n_terminals, 0));
2116			n += 1;
2117		}
2118		self.tables_size += lookahead_and_action.len() * (sz_code_type + sz_action_type).abs() as usize;
2119
2120		// Output the SHIFT_OFFSET[] table
2121		let mut shift_offset = Vec::with_capacity(acttab.n_shift_offset);
2122		for stp in states.array.iter().take(acttab.n_shift_offset)
2123		{	shift_offset.push(if stp.token_offset==std::isize::MIN {acttab.min_token_offset - 1} else {stp.token_offset});
2124		}
2125		self.tables_size += shift_offset.len() * sz_shift_offset_type.abs() as usize;
2126
2127		// Output the REDUCE_OFFSET[] table
2128		let mut reduce_offset = Vec::with_capacity(acttab.reduce_count);
2129		for stp in states.array.iter().take(acttab.reduce_count)
2130		{	reduce_offset.push(if stp.nt_offset==std::isize::MIN {acttab.min_nt_offset - 1} else {stp.nt_offset});
2131		}
2132		self.tables_size += reduce_offset.len() * sz_reduce_offset_type.abs() as usize;
2133
2134		// Output the default action table
2135		let mut default = Vec::with_capacity(states.n_no_tail);
2136		for stp in states.array.iter().take(states.n_no_tail)
2137		{	default.push(if stp.default_reduce_action!=std::usize::MAX {stp.default_reduce_action + self.min_reduce} else {self.error_action});
2138		}
2139		self.tables_size += default.len() * sz_action_type.abs() as usize;
2140
2141		// Generate the table of fallback tokens
2142		let mut fallback = Vec::new();
2143		if self.has_fallback
2144		{	fallback.reserve(acttab.n_fallbacks);
2145			for symbol in symbols.array.iter().take(acttab.n_fallbacks)
2146			{	if symbol.fallback_index != std::usize::MAX
2147				{	let fb = &symbols.array[symbol.fallback_index];
2148					fallback.push((fb.index, Arc::clone(&symbol.name), Arc::clone(&fb.name)));
2149				}
2150				else
2151				{	fallback.push((0, Arc::clone(&symbol.name), Arc::new(String::new())));
2152				}
2153			}
2154		}
2155		self.tables_size += fallback.len() * sz_code_type.abs() as usize;
2156
2157		// Generate a table containing the symbolic name of every symbol
2158		let mut token_names = Vec::new();
2159		if self.with_trace && symbols.n_symbols!=0
2160		{	token_names.reserve(symbols.n_symbols);
2161			for symbol in symbols.array.iter().take(symbols.n_symbols)
2162			{	token_names.push(Arc::clone(&symbol.name));
2163			}
2164		}
2165
2166		// Generate code which execution during each REDUCE action
2167		for sym in symbols.array.iter()
2168		{	for n_rule in sym.sym_rules_arr.iter()
2169			{	self.translate_code(&mut rules[*n_rule])?;
2170			}
2171		}
2172
2173		let start_type = symbols.get_start_symbol().data_type.clone();
2174		let minor_type = self.get_minor_type(&mut symbols);
2175		let n_symbols = symbols.n_symbols;
2176		let n_states = states.array.len();
2177		let n_no_tail = states.n_no_tail;
2178		let error_symbol = if let Some(symbol) = symbols.get_error_symbol() {symbol.index} else {0};
2179		let n_terminals = symbols.n_terminals;
2180		let n_nonterminals = symbols.n_symbols - symbols.n_terminals;
2181
2182		Ok
2183		(	LemonMint
2184			{	symbols,
2185				rules,
2186				states,
2187				token_type: self.token_type,
2188				vartype: self.vartype,
2189				start_name: self.start_name,
2190				start_type,
2191				extra_argument_type: self.extra_argument_type,
2192				extracode: self.extracode,
2193				minor_type,
2194				token,
2195
2196				sz_code_type,
2197				sz_action_type,
2198				sz_shift_offset_type,
2199				sz_reduce_offset_type,
2200
2201				n_symbols,
2202				n_states,
2203				n_no_tail,
2204				n_fallbacks: acttab.n_fallbacks,
2205				error_symbol,
2206				with_fallback: self.has_fallback,
2207				shift_count: acttab.n_shift_offset-1,
2208				reduce_count: acttab.reduce_count-1,
2209				with_trace: self.with_trace,
2210				trace_prompt: self.trace_prompt,
2211				shift_min: acttab.min_token_offset,
2212				shift_max: acttab.max_token_offset,
2213				reduce_min: acttab.min_nt_offset,
2214				reduce_max: acttab.max_nt_offset,
2215
2216				n_terminals,
2217				n_nonterminals,
2218				tables_size: self.tables_size,
2219				n_action_table_entries: self.n_action_table_entries,
2220
2221				lookahead_and_action,
2222				shift_offset,
2223				reduce_offset,
2224				default,
2225				fallback,
2226				token_names,
2227			}
2228		)
2229	}
2230
2231	/// Load a Y-grammar file. You can call this function several times to load grammar by parts, and you can call other builder methods to add/override settings.
2232	pub fn load_y_file(self, filename: &Arc<String>) -> ParserResult<Self>
2233	{	self.load_y(filename, File::open(filename.as_ref()).map_err(|e| LemonMintError::new(filename, 1, e.to_string()))?)
2234	}
2235
2236	/// Like load_y_file(), but you give file contents as io::Read object.
2237	///
2238	/// # Example
2239	///
2240	/// ```
2241	/// use lemon_mint::LemonMintBuilder;
2242	/// use std::sync::Arc;
2243	///
2244	/// let fake_filename = Arc::new("source.y".to_string()); // will appear in error messages
2245	/// let builder = LemonMintBuilder::new().load_y(&fake_filename, "%token_type {f64}\nUnit ::= NEW_LINE.".as_bytes()).unwrap();
2246	/// ```
2247	pub fn load_y<R>(mut self, filename: &Arc<String>, input: R) -> ParserResult<Self> where R: io::Read
2248	{	let input = BufReader::new(input);
2249		let mut n_line = 0;
2250		let mut lines = input.lines();
2251		let mut part_till_comment: Option<String> = None; // if a multiline comment opened on a line, this line is not complete, and it will be stored here, and we will wait to closing token
2252'l:		while let Some(line) = lines.next()
2253		{	n_line += 1;
2254			let mut line = line.map_err(|e| LemonMintError::new(filename, n_line, e.to_string()))?;
2255			// comments?
2256			if let Some(part) = part_till_comment.take()
2257			{	if let Some(pos) = line.find("*/")
2258				{	line.replace_range(.. pos+2, &part);
2259				}
2260				else
2261				{	part_till_comment = Some(part);
2262					continue;
2263				}
2264			}
2265			loop
2266			{	if let Some(pos) = line.find('/')
2267				{	match line.bytes().skip(pos+1).next()
2268					{	Some(b'/') => // line comment
2269						{	line.truncate(pos);
2270						}
2271						Some(b'*') => // multiline comment
2272						{	if let Some(len_minus_2) = line[pos+2 ..].find("*/")
2273							{	line.replace_range(pos .. pos+len_minus_2+2, "");
2274								continue;
2275							}
2276							else
2277							{	line.truncate(pos);
2278								part_till_comment = Some(line);
2279								continue 'l;
2280							}
2281						}
2282						_ => {}
2283					}
2284				}
2285				break;
2286			}
2287			// comments cut from line
2288			let mut line = line.trim();
2289			if !line.is_empty()
2290			{	let mut directive = Directive::Rule;
2291				let mut symbol_name: Cow<str> = "".into();
2292				let mut rule_rhs: Cow<str> = "".into();
2293				if line.as_bytes()[0] == b'%'
2294				{	let pos = line.bytes().position(|c| c.is_ascii_whitespace()).unwrap_or(line.len());
2295					let token = &line[1 .. pos];
2296					line = &line[pos ..].trim_start();
2297					directive = match token
2298					{	"token_type" => Directive::TokenType,
2299						"type" => Directive::Type,
2300						"default_type" => Directive::DefaultType,
2301						"start_symbol" => Directive::StartSymbol,
2302						"trace" => Directive::Trace,
2303						"extra_argument" => Directive::ExtraArgument,
2304						"left" => Directive::Left,
2305						"right" => Directive::Right,
2306						"nonassoc" => Directive::Nonassoc,
2307						"fallback" => Directive::Fallback,
2308						"code" | "include" => Directive::Code,
2309						_ =>
2310						{	return Err(LemonMintError::new(filename, n_line, format!("Directive not supported: %{}", token)));
2311						}
2312					};
2313				}
2314				match directive
2315				{	Directive::Type | Directive::Fallback =>
2316					{	// read symbol name
2317						let pos = line.bytes().position(|c| !c.is_ascii_alphanumeric() && c!=b'_').unwrap_or(line.len());
2318						if pos == 0
2319						{	return Err(LemonMintError::new(filename, n_line, "Expected symbol name after %type".to_string()));
2320						}
2321						symbol_name = line[.. pos].to_string().into();
2322						line = &line[pos ..].trim_start();
2323					}
2324					Directive::Rule =>
2325					{	let pos = line.find("::=").ok_or_else(|| LemonMintError::new(filename, n_line, "Couldn't interpret this line".to_string()))?;
2326						symbol_name = line[.. pos].trim_end().to_string().into();
2327						line = &line[pos+3 ..].trim_start();
2328						let pos = line.find('.').ok_or_else(|| LemonMintError::new(filename, n_line, "Rules must be terminated with a dot".to_string()))?;
2329						rule_rhs = line[.. pos].trim_end().to_string().into();
2330						line = &line[pos+1 ..].trim_start();
2331					}
2332					_ => {}
2333				}
2334				let mut value: Cow<str> = line.into();
2335				if line.bytes().next() == Some(b'{')
2336				{	line = &line[1 ..].trim_start(); // skip '{' at the beginning
2337					let (mut balance, mut last_close) = (1, usize::MAX);
2338					Self::balanced_braces(filename, n_line, line, &mut balance, &mut last_close)?;
2339					if balance == 0
2340					{	value = line[.. last_close].into(); // cut '}' at the end
2341					}
2342					else
2343					{	// read lines untill all braces closed
2344						let mut buffer = String::with_capacity(128);
2345						buffer.push_str(line);
2346						buffer.push('\n');
2347						let from_n_line = n_line;
2348						while let Some(line) = lines.next()
2349						{	n_line += 1;
2350							let line = line.map_err(|e| LemonMintError::new(filename, n_line, e.to_string()))?;
2351							Self::balanced_braces(filename, n_line, &line, &mut balance, &mut last_close)?;
2352							if balance == 0
2353							{	buffer.push_str(&line[.. last_close]); // cut '}' at the end
2354								break;
2355							}
2356							buffer.push_str(&line);
2357							buffer.push('\n');
2358						}
2359						if balance > 0
2360						{	return Err(LemonMintError::new(filename, n_line, format!("Braces not closed at the end of file since line {}", from_n_line)));
2361						}
2362						value = buffer.into();
2363					}
2364				}
2365				else if !line.is_empty() && line.as_bytes()[line.len()-1]==b'.'
2366				{	value = line[.. line.len()-1].trim_end().into(); // cut '.' at end
2367				}
2368				self = match directive
2369				{	Directive::Rule => self.add_rule(filename, n_line, symbol_name.into(), rule_rhs.as_ref(), value.into()),
2370					Directive::TokenType => self.set_token_type(value.into()),
2371					Directive::Type => self.add_type(filename, n_line, symbol_name.into(), value.into()),
2372					Directive::DefaultType => self.set_default_type(value.into()),
2373					Directive::StartSymbol => self.set_start_symbol(filename, n_line, value.into()),
2374					Directive::Trace => self.set_trace_prompt(value.into()),
2375					Directive::ExtraArgument => self.set_extra_argument_type(value.into()),
2376					Directive::Left => self.set_left(filename, n_line, value.as_ref()),
2377					Directive::Right => self.set_right(filename, n_line, value.as_ref()),
2378					Directive::Nonassoc => self.set_nonassoc(filename, n_line, value.as_ref()),
2379					Directive::Fallback => self.add_fallback(filename, n_line, symbol_name.into(), value.as_ref()),
2380					Directive::Code => self.add_code(value.into()),
2381				}?;
2382			}
2383		}
2384		Ok(self)
2385	}
2386
2387	fn balanced_braces(filename: &Arc<String>, n_line: usize, line: &str, balance: &mut i32, last_close: &mut usize) -> ParserResult<()>
2388	{	for (i, c) in line.bytes().enumerate()
2389		{	match c
2390			{	b'{' => *balance += 1,
2391				b'}' => {*balance -= 1; *last_close = i}
2392				_ => {}
2393			}
2394		}
2395		if *balance < 0
2396		{	return Err(LemonMintError::new(filename, n_line, "Braces on line not balanced".to_string()));
2397		}
2398		if *balance == 0
2399		{	if !line[*last_close+1 ..].trim_end().is_empty()
2400			{	return Err(LemonMintError::new(filename, n_line, "Junk after closing brace".to_string()));
2401			}
2402		}
2403		Ok(())
2404	}
2405
2406	///	Set the parser "%start_symbol".
2407	pub fn set_start_symbol(mut self, filename: &Arc<String>, n_line: usize, mut value: String) -> ParserResult<Self>
2408	{	let trimmed = value.trim();
2409		if trimmed.len() != value.len()
2410		{	value = trimmed.to_string();
2411		}
2412		if value.find(|c: char| !c.is_ascii_alphanumeric() && c!='_').is_some()
2413		{	return Err(LemonMintError::new(filename, n_line, format!("Invalid start symbol name: {}", value)));
2414		}
2415		if is_terminal_name(&value)
2416		{	return Err(LemonMintError::new(filename, n_line, "Start symbol must be nonterminal".to_string()));
2417		}
2418		self.start_name = value;
2419		Ok(self)
2420	}
2421
2422	///	Set the parser "%token_type".
2423	pub fn set_token_type(mut self, value: String) -> ParserResult<Self>
2424	{	self.token_type = typename_to_string(value);
2425		Ok(self)
2426	}
2427
2428	///	Set the parser "%default_type".
2429	pub fn set_default_type(mut self, value: String) -> ParserResult<Self>
2430	{	self.vartype = typename_to_string(value);
2431		Ok(self)
2432	}
2433
2434	///	Enable trace, and set prompt that will be printed before each message.
2435	/// The prompt can be empty string.
2436	pub fn set_trace_prompt(mut self, value: String) -> ParserResult<Self>
2437	{	self.with_trace = true;
2438		self.trace_prompt = value;
2439		Ok(self)
2440	}
2441
2442	/// Set the parser %extra_argument.
2443	/// Only it's type, like:
2444	///
2445	/// ```
2446	/// # use lemon_mint::LemonMintBuilder;
2447	///
2448	/// let builder = LemonMintBuilder::new().set_extra_argument_type("String".to_string()).unwrap();
2449	/// ```
2450	///
2451	/// In your rust code that uses the generated parser, you initialize the extra argument when you create a Parser object:
2452	///
2453	/// ```ignore
2454	/// %code {
2455	/// 	fn main()
2456	/// 	{	let mut parser = Parser::new("Initial value".to_string()); // Initial value of the extra argument
2457	/// 		assert_eq!(parser.extra, "Initial value".to_string());
2458	/// 	}
2459	/// }
2460	/// ```
2461	///
2462	/// In actions code, the extra argument is available as variable `&mut extra`:
2463	///
2464	/// ```ignore
2465	/// %token_type {String}
2466	/// Unit ::= NEW_LINE(tok). extra.push_str(&tok);
2467	/// ```
2468	pub fn set_extra_argument_type(mut self, value: String) -> ParserResult<Self>
2469	{	self.extra_argument_type = typename_to_string(value);
2470		Ok(self)
2471	}
2472
2473	///	Add the parser "%left A B C".
2474	///
2475	/// # Example
2476	///
2477	/// ```
2478	/// # use lemon_mint::LemonMintBuilder;
2479	/// # use std::sync::Arc;
2480	///
2481	/// let fake_filename = Arc::new("source.y".to_string()); // will appear in error messages
2482	/// let builder = LemonMintBuilder::new().set_left(&fake_filename, 1, "PLUS MINUS").unwrap().set_left(&fake_filename, 2, "TIMES DIVIDE").unwrap();
2483	/// ```
2484	///
2485	/// * symbol_names - Terminal symbol names, separated by whitespace characters. All the symbols will have the same precedence.
2486	/// Further calls to `set_left()`, `set_right()` or `set_nonassoc()` will set higher precedence.
2487	pub fn set_left(self, filename: &Arc<String>, n_line: usize, symbol_names: &str) -> ParserResult<Self>
2488	{	self.add_associativity(filename, n_line, symbol_names, Associativity::LEFT)
2489	}
2490
2491	///	Add the parser "%right A B C".
2492	pub fn set_right(self, filename: &Arc<String>, n_line: usize, symbol_names: &str) -> ParserResult<Self>
2493	{	self.add_associativity(filename, n_line, symbol_names, Associativity::RIGHT)
2494	}
2495
2496	///	Add the parser "%nonassoc A B C".
2497	pub fn set_nonassoc(self, filename: &Arc<String>, n_line: usize, symbol_names: &str) -> ParserResult<Self>
2498	{	self.add_associativity(filename, n_line, symbol_names, Associativity::NONASSOC)
2499	}
2500
2501	fn add_associativity(mut self, filename: &Arc<String>, n_line: usize, symbol_names: &str, assoc: Associativity) -> ParserResult<Self>
2502	{	for symbol_name in symbol_names.trim().split(|c: char| c.is_ascii_whitespace())
2503		{	if !symbol_name.is_empty()
2504			{	if symbol_name.find(|c: char| !c.is_ascii_alphanumeric() && c!='_').is_some()
2505				{	return Err(LemonMintError::new(filename, n_line, format!("Invalid token name: {}", symbol_name)));
2506				}
2507				if !is_terminal_name(symbol_name)
2508				{	return Err(LemonMintError::new(filename, n_line, format!("Can only set precedence for terminal symbols, not \"{}\"", symbol_name)));
2509				}
2510				if let Some(prev) = self.precedence.get(symbol_name)
2511				{	return Err(LemonMintError::new(filename, n_line, format!("Symbol \"{}\" has already be given a precedence at {}:{}", symbol_name, prev.filename, prev.n_line)));
2512				}
2513				self.precedence.insert
2514				(	symbol_name.to_string(),
2515					PrecedenceInFile
2516					{	filename: Arc::clone(filename),
2517						n_line,
2518						assoc,
2519						precedence: self.prec_counter,
2520					}
2521				);
2522			}
2523		}
2524		self.prec_counter += 1;
2525		Ok(self)
2526	}
2527
2528	///	Add the parser "%type symbol_name {Type}".
2529	pub fn add_type(mut self, filename: &Arc<String>, n_line: usize, mut symbol_name: String, type_name: String) -> ParserResult<Self>
2530	{	let trimmed = symbol_name.trim();
2531		if trimmed.len() != symbol_name.len()
2532		{	symbol_name = trimmed.to_string();
2533		}
2534		if symbol_name.find(|c: char| !c.is_ascii_alphanumeric() && c!='_').is_some()
2535		{	return Err(LemonMintError::new(filename, n_line, format!("Invalid symbol name: {}", symbol_name)));
2536		}
2537		if is_terminal_name(&symbol_name)
2538		{	return Err(LemonMintError::new(filename, n_line, format!("Can only set type for nonterminal symbols, not \"{}\"", symbol_name)));
2539		}
2540		if let Some(prev) = self.nonterminal_types.get(&symbol_name)
2541		{	return Err(LemonMintError::new(filename, n_line, format!("Type for symbol \"{}\" already defined at {}:{}", symbol_name, prev.filename, prev.n_line)));
2542		}
2543		self.nonterminal_types.insert
2544		(	symbol_name,
2545			StringInFile
2546			{	filename: Arc::clone(filename),
2547				n_line,
2548				string: typename_to_string(type_name),
2549			}
2550		);
2551		Ok(self)
2552	}
2553
2554	/// Return `Some((filename, n_line))` if given symbol was added through `add_type()`.
2555	pub fn get_type(&self, mut symbol_name: &str) -> Option<(Arc<String>, usize)>
2556	{	symbol_name = symbol_name.trim();
2557		self.nonterminal_types.get(symbol_name).map(|v| (Arc::clone(&v.filename), v.n_line))
2558	}
2559
2560	///	Add the parser "%fallback FB A B C".
2561	pub fn add_fallback(mut self, filename: &Arc<String>, n_line: usize, mut fallback_to_symbol_name: String, symbol_names: &str) -> ParserResult<Self>
2562	{	let trimmed = fallback_to_symbol_name.trim();
2563		if trimmed.len() != fallback_to_symbol_name.len()
2564		{	fallback_to_symbol_name = trimmed.to_string();
2565		}
2566		if fallback_to_symbol_name.find(|c: char| !c.is_ascii_alphanumeric() && c!='_').is_some()
2567		{	return Err(LemonMintError::new(filename, n_line, format!("Invalid token name: {}", fallback_to_symbol_name)));
2568		}
2569		let fallback_to_symbol_name = Arc::new(fallback_to_symbol_name);
2570		for symbol_name in symbol_names.trim().split(|c: char| c.is_ascii_whitespace())
2571		{	if !symbol_name.is_empty()
2572			{	if symbol_name.find(|c: char| !c.is_ascii_alphanumeric() && c!='_').is_some()
2573				{	return Err(LemonMintError::new(filename, n_line, format!("Invalid token name: {}", symbol_name)));
2574				}
2575				if !is_terminal_name(symbol_name)
2576				{	return Err(LemonMintError::new(filename, n_line, format!("Can only set fallback to terminal symbols, not \"{}\"", symbol_name)));
2577				}
2578				let symbol_name = Arc::new(symbol_name.to_string());
2579				self.symbols_builder.add(&symbol_name);
2580				self.symbols_builder.add(&fallback_to_symbol_name);
2581				let sp = self.symbols_builder.get(&symbol_name);
2582				if sp.fallback_index != std::usize::MAX
2583				{	return Err(LemonMintError::new(filename, n_line, format!("More than one fallback assigned to token \"{}\"", symbol_name)));
2584				}
2585				let fsp = self.symbols_builder.get(&fallback_to_symbol_name);
2586				if *fsp == *sp
2587				{	return Err(LemonMintError::new(filename, n_line, format!("Symbol \"{}\" is asked fallback to self // {}, {}", symbol_name, fallback_to_symbol_name, symbol_name)));
2588				}
2589				self.symbols_builder.get_mut(&symbol_name).fallback_index = fsp.index;
2590				self.has_fallback = true;
2591			}
2592		}
2593		Ok(self)
2594	}
2595
2596	///	Add parser rule like "a", "b(v_b) COMMA c(v_c)", "vec![v_b, v_c]"
2597	pub fn add_rule(mut self, filename: &Arc<String>, n_line: usize, mut lhs_name: String, rhs_names_aliases: &str, code: String) -> ParserResult<Self>
2598	{	let trimmed = lhs_name.trim();
2599		if trimmed.len() != lhs_name.len()
2600		{	lhs_name = trimmed.to_string();
2601		}
2602		if is_terminal_name(&lhs_name)
2603		{	return Err(LemonMintError::new(filename, n_line, format!("Invalid LHS symbol: \"{}\"", lhs_name)));
2604		}
2605		let mut code = code;
2606		if code.trim().is_empty()
2607		{	code = String::new();
2608		}
2609		if self.start_name.is_empty()
2610		{	self.start_name = lhs_name.clone();
2611		}
2612		let lhs_name = Arc::new(lhs_name);
2613		let lhs_index = self.symbols_builder.add(&lhs_name);
2614		let mut rule = Rule::new(filename, n_line, &lhs_name, lhs_index, self.rules.len(), code);
2615		// parse rhs_names_aliases
2616		let mut s = rhs_names_aliases.trim_start();
2617		while s.len() != 0
2618		{	let name_len = s.chars().position(|c| !c.is_ascii_alphanumeric() && c!='_').unwrap_or(s.len());
2619			if name_len == 0
2620			{	return Err(LemonMintError::new(filename, n_line, format!("Invalid RHS expression: \"{}\"", rhs_names_aliases)));
2621			}
2622			let rhs_name = Arc::new(s[.. name_len].to_string());
2623			let rhs_index = self.symbols_builder.add(&rhs_name);
2624			s = s[name_len ..].trim_start();
2625			let mut alias = String::new();
2626			if s.bytes().next() == Some(b'(')
2627			{	s = s[1 ..].trim_start();
2628				let alias_len = s.chars().position(|c| !c.is_ascii_alphanumeric() && c!='_').unwrap_or(s.len());
2629				alias = s[.. alias_len].to_string();
2630				s = s[alias_len ..].trim_start();
2631				if alias_len==0 || s.bytes().next() != Some(b')')
2632				{	return Err(LemonMintError::new(filename, n_line, format!("Invalid alias in RHS expression: \"{}\"", rhs_names_aliases)));
2633				}
2634				s = s[1 ..].trim_start();
2635			}
2636			rule.rhs.push(Rhs{name: rhs_name, index: rhs_index, alias});
2637		}
2638		self.symbols_builder.get_mut(&lhs_name).sym_rules_arr.insert(0, self.rules.len()); // TODO: maybe push(), not insert()
2639		self.rules.push(rule);
2640		Ok(self)
2641	}
2642
2643	///	Add the parser %code or %include
2644	pub fn add_code(mut self, code: String) -> ParserResult<Self>
2645	{	if self.extracode.is_empty()
2646		{	self.extracode = code;
2647		}
2648		else
2649		{	self.extracode.push_str("\n\n");
2650			self.extracode.push_str(&code);
2651		}
2652		Ok(self)
2653	}
2654
2655	/// Allows to disable finite-state machine tables compression. Don't do this.
2656	pub fn set_no_compress(mut self, new_no_compress: bool) -> ParserResult<Self>
2657	{	self.no_compress = new_no_compress;
2658		Ok(self)
2659	}
2660
2661	/// Disable resorting states. You don't need this functionality.
2662	pub fn set_no_resort(mut self, new_no_resort: bool) -> ParserResult<Self>
2663	{	self.no_resort = new_no_resort;
2664		Ok(self)
2665	}
2666
2667	/// When you feed all the parser rules and options, call this method to finally build the parser finite-state machine transition tables.
2668	/// If there are problems with your grammar or if there are parser conflicts, this will return Err.
2669	/// If parser build succeeds this returns the parser representation as `LemonMint` object.
2670	pub fn try_into_lemon(mut self) -> ParserResult<LemonMint>
2671	{	// rules
2672		let mut rules = mem::replace(&mut self.rules, Vec::new());
2673		if rules.len() == 0
2674		{	return Err(LemonMintError::new(&Arc::new(String::new()), 1, "Empty grammar".to_string()));
2675		}
2676
2677		// Count and index the symbols of the grammar
2678		let mut symbols =
2679		{	let symbols_builder = mem::replace(&mut self.symbols_builder, SymbolsBuilder::new(true));
2680			let nonterminal_types = mem::replace(&mut self.nonterminal_types, HashMap::new());
2681			let precedence = mem::replace(&mut self.precedence, HashMap::new());
2682
2683			symbols_builder.into_symbols(&self.start_name, nonterminal_types, precedence, &mut rules)? // symbols - Sorted array of all symbols
2684		};
2685
2686		// Put rules that have no reduce action C-code associated with them last, so that the switch() statement that selects reduction actions will have a smaller jump table.
2687		rules.sort_by
2688		(	|a, b|
2689			{	if a.code.is_empty() == b.code.is_empty()
2690				{	a.index.cmp(&b.index)
2691				}
2692				else if a.code.is_empty()
2693				{	Ordering::Greater
2694				}
2695				else
2696				{	Ordering::Less
2697				}
2698			}
2699		);
2700		for (i, rule) in rules.iter_mut().enumerate()
2701		{	rule.index = i;
2702		}
2703
2704		// Find the precedence for every production rule (that has one)
2705		Self::find_rule_precedences(&mut symbols, &mut rules);
2706
2707		// Compute the lambda-nonterminals and the first-sets for every nonterminal
2708		self.find_first_sets(&mut symbols, &mut rules);
2709
2710		// Find the start symbol
2711		if !self.start_name.is_empty()
2712		{	if symbols.start_symbol_index == std::usize::MAX
2713			{	return Err(LemonMintError::new(&Self::get_filename_of_first_rule(&rules), 1, format!("The specified start symbol \"{}\" is not in a nonterminal of the grammar", self.start_name)));
2714			}
2715		}
2716		else
2717		{	return Err(LemonMintError::new(&Self::get_filename_of_first_rule(&rules), 1, "Please, specify a start symbol".to_string()));
2718		}
2719
2720		// Make sure the start symbol doesn't occur on the right-hand side of any rule.  Report an error if it does.
2721		// (YACC would generate a new start symbol in this case.)
2722		for rule in rules.iter()
2723		{	for rhs in &rule.rhs
2724			{	if rhs.index == symbols.start_symbol_index
2725				{	return Err(LemonMintError::new(&Self::get_filename_of_first_rule(&rules), 1, format!("The start symbol \"{}\" occurs on the right-hand side of a rule", rhs.name)));
2726				}
2727			}
2728		}
2729
2730		dump_symbols(&symbols, &rules);
2731
2732		// Compute all LR(0) states.  Also record follow-set propagation links so that the follow-set can be computed later
2733		let mut states = StatesBuilder::build(&symbols, &mut rules, symbols.get_start_symbol(), symbols.n_terminals, &mut self.actions_enum)?;
2734
2735		dump_states(&states, &rules, &symbols, 1);
2736
2737		// Tie up loose ends on the propagation links
2738		Self::find_links(&states);
2739
2740		dump_states(&states, &rules, &symbols, 2);
2741
2742		// Compute the follow set of every reducible configuration
2743		Self::find_follow_sets(&states);
2744
2745		dump_states(&states, &rules, &symbols, 3);
2746
2747		// Compute the action tables
2748		self.find_actions(&symbols, &mut rules, &mut states)?;
2749
2750		dump_states(&states, &rules, &symbols, 4);
2751
2752		// Compress the action tables
2753		if !self.no_compress
2754		{	self.compress_tables(&symbols, &rules, &mut states, symbols.default_symbol_index);
2755		}
2756
2757		dump_states(&states, &rules, &symbols, 5);
2758
2759		// Reorder and renumber the states so that states with fewer choices occur at the end.  This is an optimization that helps make the
2760		// generated parser tables smaller.
2761		if !self.no_resort
2762		{	self.resort_states(&symbols, &mut states);
2763		}
2764
2765		dump_states(&states, &rules, &symbols, 6);
2766
2767		// Compute the action table
2768		self.min_shift_reduce = states.array.len();
2769		self.error_action = self.min_shift_reduce + rules.len();
2770		self.accept_action = self.error_action + 1;
2771		self.no_action = self.accept_action + 1;
2772		self.min_reduce = self.no_action + 1;
2773		self.max_action = self.min_reduce + rules.len();
2774		let acttab = self.init_acttab(&symbols, &mut rules, &mut states);
2775
2776		dump_states(&states, &rules, &symbols, 7);
2777
2778		// Generate the source code for the parser
2779		if self.n_conflicts > 0
2780		{	Err(LemonMintError::new(&Self::get_filename_of_first_rule(&rules), 1, format!("{} parsing conflicts", self.n_conflicts)))
2781		}
2782		else
2783		{	self.get_lemon(symbols, rules, states, acttab)
2784		}
2785	}
2786}
2787
2788#[derive(Debug, Copy, Clone, PartialEq)]
2789enum Lang
2790{	Rust
2791}
2792
2793fn size_type_to_str(lang: Lang, n_bytes: isize) -> &'static str
2794{	match (lang, n_bytes)
2795	{	(Lang::Rust, -1) => "i8",
2796		(Lang::Rust, -2) => "i16",
2797		(Lang::Rust, -4) => "i32",
2798		(Lang::Rust,  1) => "u8",
2799		(Lang::Rust,  2) => "u16",
2800		(Lang::Rust,  4) => "u32",
2801		(Lang::Rust,  _) => "isize",
2802	}
2803}
2804
2805/// The compiled parser that can be saved to a rust file. Use `LemonMintBuilder` to build it.
2806#[derive(Debug)]
2807pub struct LemonMint
2808{	symbols: Symbols,
2809	rules: Vec<Rule>,                  // All rules
2810	states: States,
2811	token_type: String,                // Type of terminal symbols in the parser stack
2812	vartype: String,                   // The default type of non-terminal symbols
2813	start_name: String,                // Name of the start symbol for the grammar
2814	start_type: String,
2815	extra_argument_type: String,
2816	extracode: String,
2817	minor_type: Vec<(String, String)>,
2818	token: Vec<Arc<String>>,
2819
2820	sz_code_type: isize,
2821	sz_action_type: isize,
2822	sz_shift_offset_type: isize,
2823	sz_reduce_offset_type: isize,
2824
2825	n_symbols: usize,
2826	n_states: usize,
2827	n_no_tail: usize,
2828	n_fallbacks: usize,
2829	error_symbol: usize,
2830	#[allow(dead_code)] with_fallback: bool,
2831	shift_count: usize,
2832	reduce_count: usize,
2833	with_trace: bool,
2834	trace_prompt: String,              // Prompt to preface each trace message, if with_trace is true
2835	shift_min: isize,
2836	shift_max: isize,
2837	reduce_min: isize,
2838	reduce_max: isize,
2839
2840	n_terminals: usize,
2841	#[allow(dead_code)] n_nonterminals: usize,
2842	#[allow(dead_code)] tables_size: usize,                // Total table size of all tables in bytes
2843	n_action_table_entries: usize,     // Number of entries in the yy_action[] table
2844
2845	lookahead_and_action: Vec<(usize, usize)>,
2846	shift_offset: Vec<isize>,
2847	reduce_offset: Vec<isize>,
2848	default: Vec<usize>,
2849	fallback: Vec<(usize, Arc<String>, Arc<String>)>,
2850	token_names: Vec<Arc<String>>,
2851}
2852impl LemonMint
2853{	/// Generate Rust source code for the parser
2854	pub fn gen_rust<W>(&self, out: &mut W) -> io::Result<()> where W: io::Write
2855	{	writeln!(out, "pub mod code {{")?;
2856
2857		let mut lempar_reader = LemparReader::new();
2858		lempar_reader.copy_part(out)?; // to %% no. 1
2859
2860		// Generate types
2861		writeln!(out, "pub type TokenValue = {};", if !self.token_type.is_empty() {&self.token_type} else {"String"})?;
2862		writeln!(out, "pub type ExtraArgumentType = {};", if !self.extra_argument_type.is_empty() {&self.extra_argument_type} else {"()"})?;
2863		writeln!(out, "pub type StartType = {};", if !self.start_type.is_empty() {&self.start_type} else {"()"})?;
2864		writeln!(out, "type CodeType = {};", size_type_to_str(Lang::Rust, self.sz_code_type))?;
2865		writeln!(out, "type ActionType = {};", size_type_to_str(Lang::Rust, self.sz_action_type))?;
2866		writeln!(out, "type ShiftOffsetType = {};", size_type_to_str(Lang::Rust, self.sz_shift_offset_type))?;
2867		writeln!(out, "type ReduceOffsetType = {};", size_type_to_str(Lang::Rust, self.sz_reduce_offset_type))?;
2868
2869		write!(out, "enum MinorType\n{{")?;
2870		for (variant, typ) in self.minor_type.iter()
2871		{	if typ.is_empty()
2872			{	writeln!(out, "\t{},", variant)?;
2873			}
2874			else
2875			{	writeln!(out, "\t{}({}),", variant, typ)?;
2876			}
2877		}
2878		writeln!(out, "}}")?;
2879
2880		// Generate token constants
2881		writeln!(out, "#[repr(u32)]\n#[derive(Copy, Clone, PartialEq)]\n#[allow(non_camel_case_types)]")?;
2882		write!(out, "pub enum Token\n{{")?;
2883		for (i, name) in self.token.iter().enumerate()
2884		{	if self.token_type.is_empty()
2885			{	writeln!(out, "\t{:<30} = {:2},", name, i+1)?;
2886			}
2887			else
2888			{	writeln!(out, "\t{:<30} = {:2},", name, i+1)?;
2889			}
2890		}
2891		writeln!(out, "}}\n")?;
2892
2893		// Generate constants
2894		writeln!(out, "const NO_CODE: CodeType = {}; // YYNOCODE", self.n_symbols)?;
2895		writeln!(out, "const N_STATES: usize = {}; // YYNSTATE", self.n_no_tail)?;
2896		writeln!(out, "const N_RULES: usize = {}; // YYNRULE", self.rules.len())?;
2897		writeln!(out, "const N_TERMINALS: usize = {}; // YYNTOKEN", self.n_terminals)?;
2898		writeln!(out, "const MAX_SHIFT: usize = N_STATES-1; // YY_MAX_SHIFT")?;
2899		writeln!(out, "const MIN_SHIFTREDUCE: usize = {}; // YY_MIN_SHIFTREDUCE", self.n_states)?;
2900		writeln!(out, "const MAX_SHIFTREDUCE: usize = MIN_SHIFTREDUCE + N_RULES - 1; // YY_MAX_SHIFTREDUCE")?;
2901		writeln!(out, "const ERROR_ACTION: usize = MAX_SHIFTREDUCE + 1; // YY_ERROR_ACTION")?;
2902		writeln!(out, "const ACCEPT_ACTION: usize = ERROR_ACTION + 1; // YY_ACCEPT_ACTION")?;
2903		writeln!(out, "const NO_ACTION: usize = ACCEPT_ACTION + 1; // YY_NO_ACTION")?;
2904		writeln!(out, "const MIN_REDUCE: usize = NO_ACTION + 1; // YY_MIN_REDUCE")?;
2905		writeln!(out, "//const MAX_REDUCE: usize = MIN_REDUCE + N_RULES - 1; // YY_MAX_REDUCE")?;
2906		writeln!(out, "const ERROR_SYMBOL: CodeType = {}; // YYERRORSYMBOL", self.error_symbol)?;
2907		writeln!(out, "const WITH_FALLBACK: bool = {}; // YYFALLBACK", if self.n_fallbacks>0 {"true"} else {"false"})?;
2908		writeln!(out, "const SHIFT_COUNT: usize = {}; // YY_SHIFT_COUNT", self.shift_count)?;
2909		writeln!(out, "const REDUCE_COUNT: usize = {}; // YY_REDUCE_COUNT", self.reduce_count)?;
2910		writeln!(out, "//const SHIFT_MIN: i32 = {}; // YY_SHIFT_MIN", self.shift_min)?;
2911		writeln!(out, "//const SHIFT_MAX: i32 = {}; // YY_SHIFT_MAX", self.shift_max)?;
2912		writeln!(out, "//const REDUCE_MIN: i32 = {}; // YY_REDUCE_MIN", self.reduce_min)?;
2913		writeln!(out, "//const REDUCE_MAX: i32 = {}; // YY_REDUCE_MAX", self.reduce_max)?;
2914		writeln!(out, "const ACTTAB_COUNT: usize = {}; // YY_ACTTAB_COUNT", self.n_action_table_entries)?;
2915		writeln!(out, "const TRACE: bool = {};", if self.with_trace {"true"} else {"false"})?;
2916
2917		// trace
2918		if self.trace_prompt.chars().position(|c| c=='\\' || c=='"').is_none()
2919		{	writeln!(out, "const TRACE_PROMPT: &str = \"{}\";", self.trace_prompt)?;
2920		}
2921		else
2922		{	let mut tag = String::with_capacity(self.trace_prompt.len()+1);
2923			for _i in 0 .. self.trace_prompt.len()+1
2924			{	tag.push('#');
2925				if !self.trace_prompt.contains(&tag)
2926				{	break;
2927				}
2928			}
2929			writeln!(out, "const TRACE_PROMPT: &str = r{tag}\"{}\"{tag};", self.trace_prompt, tag=tag)?;
2930		}
2931
2932		// Generate the action table and its associates:
2933		//
2934		//  yy_action[]        A single table containing all actions.
2935		//  yy_lookahead[]     A table containing the lookahead for each entry in
2936		//                     yy_action.  Used to detect hash collisions.
2937		//  SHIFT_OFFSET[]    For each state, the offset into yy_action for
2938		//                     shifting terminals.
2939		//  REDUCE_OFFSET[]   For each state, the offset into yy_action for
2940		//                     shifting non-terminals after a reduce.
2941		//  DEFAULT[]       Default action for each state.
2942
2943		// Output the LOOKAHEAD_AND_ACTION table
2944		write!(out, "const LOOKAHEAD_AND_ACTION: [LookaheadAndAction; {}] =", self.lookahead_and_action.len())?;
2945		let mut formatter = ArrayFormatter::new(2);
2946		for (lookahead, action) in self.lookahead_and_action.iter()
2947		{	formatter.separ(out)?;
2948			write!(out, "LookaheadAndAction {{lookahead: {:4}, action: {:4}}}", lookahead, action)?;
2949		}
2950		formatter.end(out)?;
2951
2952		// Output the SHIFT_OFFSET[] table
2953		write!(out, "const SHIFT_OFFSET: [ShiftOffsetType; {}] =", self.shift_offset.len())?;
2954		let mut formatter = ArrayFormatter::new(16);
2955		for offset in self.shift_offset.iter()
2956		{	formatter.separ(out)?;
2957			write!(out, "{:4}", offset)?;
2958		}
2959		formatter.end(out)?;
2960
2961		// Output the REDUCE_OFFSET[] table
2962		write!(out, "const REDUCE_OFFSET: [ReduceOffsetType; {}] =", self.reduce_offset.len())?;
2963		let mut formatter = ArrayFormatter::new(16);
2964		for offset in self.reduce_offset.iter()
2965		{	formatter.separ(out)?;
2966			write!(out, "{:4}", offset)?;
2967		}
2968		formatter.end(out)?;
2969
2970		// Output the default action table
2971		write!(out, "const DEFAULT: [ActionType; {}] =", self.default.len())?;
2972		let mut formatter = ArrayFormatter::new(16);
2973		for action in self.default.iter()
2974		{	formatter.separ(out)?;
2975			write!(out, "{:4}", action)?;
2976		}
2977		formatter.end(out)?;
2978
2979		// Next
2980		lempar_reader.copy_part(out)?; // to %% no. 2
2981
2982		// Generate the table of fallback tokens
2983		write!(out, "const FALLBACK: [CodeType; {}] =", self.fallback.len())?;
2984		let mut formatter = ArrayFormatter::new(1);
2985		for (index, name, to_name) in self.fallback.iter()
2986		{	formatter.separ(out)?;
2987			write!(out, "{:3} /* {:10} => {} */", index, name, to_name)?;
2988		}
2989		formatter.end(out)?;
2990
2991		// Next
2992		lempar_reader.copy_part(out)?; // to %% no. 3
2993
2994		// Generate a table containing the symbolic name of every symbol
2995		write!(out, "const TOKEN_NAMES: [&str; {}] =", self.token_names.len())?;
2996		let mut formatter = ArrayFormatter::new(1);
2997		for name in self.token_names.iter()
2998		{	formatter.separ(out)?;
2999			write!(out, "{:<15}", format!("\"{}\"", name))?;
3000		}
3001		formatter.end(out)?;
3002
3003		// Next
3004		lempar_reader.copy_part(out)?; // to %% no. 4
3005
3006		// Generate a table containing a text string that describes every rule in the rule set of the grammar.
3007		// This information is used when tracing REDUCE actions.
3008		write!(out, "const RULE_NAMES: [&str; {}] =", self.rules.len())?;
3009		let mut formatter = ArrayFormatter::new(1);
3010		for rule in self.rules.iter()
3011		{	formatter.separ(out)?;
3012			write!(out, "\"{}\"", rule)?;
3013		}
3014		formatter.end(out)?;
3015
3016		// Next
3017		lempar_reader.copy_part(out)?; // to %% no. 5
3018
3019		// Generate the table of rule information
3020		// Note: This code depends on the fact that rules are number sequentually beginning with 0.
3021		write!(out, "const RULES_INFO: [CodeType; {}] =", self.rules.len())?;
3022		let mut formatter = ArrayFormatter::new(16);
3023		for rule in &self.rules
3024		{	formatter.separ(out)?;
3025			write!(out, "{:4}", rule.lhs_index)?;
3026		}
3027		formatter.end(out)?;
3028
3029		// Next
3030		lempar_reader.copy_part(out)?; // to %% no. 6
3031
3032		// First output rules other than the default: rule
3033		for rule in self.rules.iter()
3034		{	if !rule.code.is_empty() // Will be default:
3035			{	write!(out, "\t\t\t{} =>", rule.index)?;
3036				let has_data_type = !self.symbols.array[rule.lhs_index].data_type.is_empty();
3037				let mut next_indent = "\t\t\t\t";
3038				if has_data_type && !rule.lhs_start
3039				{	write!(out, " MinorType::Symbol{}\n\t\t\t(\t{{", self.symbols.array[rule.lhs_index].dtnum)?;
3040					next_indent = "\t\t\t\t\t";
3041				}
3042				else
3043				{	write!(out, "\n\t\t\t{{")?;
3044				}
3045				let mut indent = "\t";
3046				let mut n_aliases = 0;
3047				let n_args = rule.rhs.len();
3048				for i in (0 .. n_args).rev()
3049				{	let has_alias = !rule.rhs[i].alias.is_empty();
3050					if has_alias
3051					{	n_aliases += 1;
3052						writeln!(out, "{}let arg{} = self.stack.pop().unwrap();", indent, i+1)?;
3053					}
3054					else
3055					{	writeln!(out, "{}self.stack.pop();", indent)?;
3056					}
3057					indent = next_indent;
3058				}
3059				if n_aliases > 0
3060				{	write!(out, "{}{}match {}", indent, if rule.lhs_start {"let result = "} else {""}, if n_aliases>1 {"("} else {""})?;
3061					let mut comma = "";
3062					for i in 0 .. n_args
3063					{	if !rule.rhs[i].alias.is_empty()
3064						{	write!(out, "{}arg{}.minor", comma, i+1)?;
3065							comma = ", ";
3066						}
3067					}
3068					write!(out, "{}\n{}{{\t{}", if n_aliases>1 {")"} else {""}, indent, if n_aliases>1 {"("} else {""})?;
3069					comma = "";
3070					for (i, rhs) in rule.rhs.iter().enumerate()
3071					{	if !rhs.alias.is_empty()
3072						{	write!(out, "{}MinorType::Symbol{}(arg{})", comma, self.symbols.array[rhs.index].dtnum, i+1)?;
3073							comma = ", ";
3074						}
3075					}
3076					write!(out, "{} => super::rules::do_rule_{}(&mut self.extra", if n_aliases>1 {")"} else {""}, rule.index)?;
3077					for i in 0 .. n_args
3078					{	if !rule.rhs[i].alias.is_empty()
3079						{	write!(out, ", arg{}", i+1)?;
3080						}
3081					}
3082					if rule.lhs_start
3083					{	writeln!(out, "),\n{}\t_ => unreachable!()\n{}}};\n\t\t\t\tself.result = Some(result);\n\t\t\t\tMinorType::None\n\t\t\t}},", indent, indent)?;
3084					}
3085					else if has_data_type
3086					{	writeln!(out, "),\n{}\t_ => unreachable!()\n{}}}\n\t\t\t\t}}\n\t\t\t),", indent, indent)?;
3087					}
3088					else
3089					{	writeln!(out, "),\n{}\t_ => unreachable!()\n{}}};\n\t\t\t\tMinorType::None\n\t\t\t}},", indent, indent)?;
3090					}
3091				}
3092				else
3093				{	if rule.lhs_start
3094					{	writeln!(out, "{}self.result = Some(super::rules::do_rule_{}(&mut self.extra));\n\t\t\t\tMinorType::None\n\t\t\t}},", indent, rule.index)?;
3095					}
3096					else if has_data_type
3097					{	writeln!(out, "{}super::rules::do_rule_{}(&mut self.extra)\n\t\t\t}}),", indent, rule.index)?;
3098					}
3099					else
3100					{	writeln!(out, "{}super::rules::do_rule_{}(&mut self.extra);\n\t\t\t\tMinorType::None\n\t\t\t}},", indent, rule.index)?;
3101					}
3102				}
3103			}
3104		}
3105		// Finally, output the default: rule.
3106		writeln!(out, "\t\t\t_ =>\n\t\t\t{{\tself.stack.pop(); MinorType::None\n\t\t\t}}")?;
3107
3108		// Next
3109		lempar_reader.copy_part(out)?; // to %% no. 7
3110
3111		writeln!(out, "\n}}\n\n\nmod rules\n{{\tuse super::code::{{TokenValue, ExtraArgumentType}};")?;
3112		for rule in self.rules.iter()
3113		{	let rule = rule;
3114			if !rule.code.is_empty()
3115			{	write!(out, "\n\t/// {}\n", rule)?;
3116				write!(out, "\t#[inline]\n\t#[allow(non_snake_case, unused_variables)]\n")?;
3117				write!(out, "\tpub fn do_rule_{}(extra: &mut ExtraArgumentType", rule.index)?;
3118				for rhs in &rule.rhs
3119				{	if !rhs.alias.is_empty()
3120					{	let data_type = if rhs.index < self.n_terminals
3121						{	"TokenValue"
3122						}
3123						else
3124						{	&self.symbols.array[rhs.index].data_type
3125						};
3126						write!(out, ", {}: {}", rhs.alias, if data_type.is_empty() {"()"} else {data_type})?;
3127					}
3128				}
3129				write!(out, ")")?;
3130				let lhs = &self.symbols.array[rule.lhs_index];
3131				if !lhs.data_type.is_empty()
3132				{	write!(out, " -> {}", lhs.data_type)?;
3133				}
3134				write!(out, "\n\t{{\t")?;
3135				let mut it = rule.code.chars();
3136'l:				while let Some(mut c) = it.next()
3137				{	'm:while c == '\n'
3138					{	write!(out, "\n\t\t")?;
3139						while let Some(c2) = it.next()
3140						{	if c2=='\n' || !c2.is_ascii_whitespace()
3141							{	c = c2;
3142								continue 'm;
3143							}
3144						}
3145						break 'l;
3146					}
3147					write!(out, "{}", c)?;
3148				}
3149				writeln!(out, "\n\t}}")?;
3150			}
3151		}
3152		writeln!(out, "}}\n")?;
3153
3154		// End
3155		lempar_reader.copy_part(out)?;
3156		if !self.extracode.is_empty()
3157		{	writeln!(out, "\n\n{}", self.extracode)?;
3158		}
3159
3160		Ok(())
3161	}
3162
3163	/// Generate a report of the parser generated.  (the "y.output" file)
3164	///
3165	/// * `basisflag` - Print only the basis in report
3166	/// * `show_precedence_conflict` - Show conflicts resolved by precedence rules
3167	pub fn gen_log<W>(&self, out: &mut W, basisflag: bool, show_precedence_conflict: bool) -> io::Result<()> where W: io::Write
3168	{	for stp in self.states.array[0 .. self.states.n_no_tail].iter()
3169		{	writeln!(out, "State {}:", stp.n_state)?;
3170
3171			for cfp in stp.configurations.iter()
3172			{	if basisflag
3173				{	let mut is_basis = false;
3174					for bp in stp.basis.iter()
3175					{	if *cfp.borrow() == *bp.borrow()
3176						{	is_basis = true;
3177							break;
3178						}
3179					}
3180					if !is_basis
3181					{	continue;
3182					}
3183				}
3184				if cfp.borrow().dot == self.rules[cfp.borrow().n_rule].rhs.len()
3185				{	let buf = format!("({})", self.rules[cfp.borrow().n_rule].index);
3186					write!(out, "    {:>5} ", buf)?;
3187				}
3188				else
3189				{	write!(out, "          ")?;
3190				}
3191				Self::config_print(&self.rules, out, cfp)?;
3192				writeln!(out, "")?;
3193			}
3194
3195			writeln!(out, "")?;
3196			for action in stp.actions.iter()
3197			{	if Self::print_action(&self.symbols, &self.rules, action, out, 30, show_precedence_conflict)?
3198				{	writeln!(out, "")?;
3199				}
3200			}
3201			writeln!(out, "")?;
3202		}
3203		writeln!(out, "----------------------------------------------------")?;
3204		writeln!(out, "Symbols:")?;
3205		for i in 0 .. self.symbols.n_symbols
3206		{	let sp = &self.symbols.array[i];
3207			write!(out, " {:>3}: {}", i, sp.name)?;
3208			if sp.typ == SymbolType::NONTERMINAL
3209			{	write!(out, ":")?;
3210				if sp.lambda
3211				{	write!(out, " <lambda>")?;
3212				}
3213				for j in 0 .. self.symbols.n_terminals
3214				{	if sp.firstset.len()>0 && sp.firstset.contains(j)
3215					{	write!(out, " {}", self.symbols.array[j].name)?;
3216					}
3217				}
3218			}
3219			writeln!(out, "")?;
3220		}
3221		Ok(())
3222	}
3223
3224	fn config_print<W>(rules: &Vec<Rule>, out: &mut W, cfp: &Rc<RefCell<Config>>) -> io::Result<()> where W: io::Write
3225	{	write!(out, "{} ::=", rules[cfp.borrow().n_rule].lhs)?;
3226		for i in 0 ..= rules[cfp.borrow().n_rule].rhs.len()
3227		{	if i == cfp.borrow().dot
3228			{	write!(out, " *")?;
3229			}
3230			if i == rules[cfp.borrow().n_rule].rhs.len()
3231			{	break;
3232			}
3233			write!(out, " {}", rules[cfp.borrow().n_rule].rhs[i].name)?;
3234		}
3235		Ok(())
3236	}
3237
3238	/// Print an action to the given file descriptor.  Return FALSE if nothing was actually printed.
3239	fn print_action<W>(symbols: &Symbols, rules: &[Rule], action: &Rc<RefCell<Action>>, out: &mut W, indent: usize, show_precedence_conflict: bool) -> io::Result<bool> where W: io::Write
3240	{	let mut result = false;
3241		match action.borrow().typ
3242		{	ActionType::Shift =>
3243			{	if let StateOrRule::State(n_state) = action.borrow().x
3244				{	write!(out, "{:>w$} shift        {:<7}", symbols.array[action.borrow().symbol_index].name, n_state, w=indent)?;
3245					result = true;
3246				}
3247			}
3248			ActionType::Reduce =>
3249			{	if let StateOrRule::Rule(n_rule) = action.borrow().x
3250				{	write!(out, "{:>w$} reduce       {:<7}", symbols.array[action.borrow().symbol_index].name, rules[n_rule].index, w=indent)?;
3251					Self::rule_print(out, &rules[n_rule], std::usize::MAX)?;
3252					result = true;
3253				}
3254			}
3255			ActionType::ShiftReduce =>
3256			{	if let StateOrRule::Rule(n_rule) = action.borrow().x
3257				{	write!(out, "{:>w$} shift-reduce {:<7}", symbols.array[action.borrow().symbol_index].name, rules[n_rule].index, w=indent)?;
3258					Self::rule_print(out, &rules[n_rule], std::usize::MAX)?;
3259					result = true;
3260				}
3261			}
3262			ActionType::Accept =>
3263			{	write!(out, "{:>w$} accept", symbols.array[action.borrow().symbol_index].name, w=indent)?;
3264				result = true;
3265			}
3266			ActionType::Error =>
3267			{	write!(out, "{:>w$} error", symbols.array[action.borrow().symbol_index].name, w=indent)?;
3268				result = true;
3269			}
3270			ActionType::SrConflict | ActionType::RrConflict =>
3271			{	if let StateOrRule::Rule(n_rule) = action.borrow().x
3272				{	write!(out, "{:>w$} reduce       {:<7} ** Parsing conflict **", symbols.array[action.borrow().symbol_index].name, rules[n_rule].index, w=indent)?;
3273					result = true;
3274				}
3275			}
3276			ActionType::SsConflict =>
3277			{	if let StateOrRule::State(n_state) = action.borrow().x
3278				{	write!(out, "{:>w$} shift        {:<7} ** Parsing conflict **", symbols.array[action.borrow().symbol_index].name, n_state, w=indent)?;
3279					result = true;
3280				}
3281			}
3282			ActionType::ShResolved =>
3283			{	if show_precedence_conflict
3284				{	if let StateOrRule::State(n_state) = action.borrow().x
3285					{	write!(out, "{:>w$} shift        {:<7} -- dropped by precedence", symbols.array[action.borrow().symbol_index].name, n_state, w=indent)?;
3286						result = true;
3287					}
3288				}
3289			}
3290			ActionType::RdResolved =>
3291			{	if show_precedence_conflict
3292				{	if let StateOrRule::Rule(n_rule) = action.borrow().x
3293					{	write!(out, "{:>w$} reduce {:<7} -- dropped by precedence", symbols.array[action.borrow().symbol_index].name, rules[n_rule].index, w=indent)?;
3294						result = true;
3295					}
3296				}
3297			}
3298			ActionType::NotUsed => {}
3299		}
3300		Ok(result)
3301	}
3302
3303	/// Print a single rule.
3304	fn rule_print<W>(out: &mut W, rule: &Rule, cursor: usize) -> io::Result<()> where W: io::Write
3305	{	write!(out, "{} ::=", rule.lhs)?;
3306		for (i, symbol) in rule.rhs.iter().enumerate()
3307		{	if i == cursor
3308			{	write!(out, " *")?;
3309			}
3310			write!(out, " {}", symbol.name)?;
3311		}
3312		if cursor == rule.rhs.len()
3313		{	write!(out, " *")?;
3314		}
3315		Ok(())
3316	}
3317
3318	// Duplicate the input file without comments and without actions on rules
3319	pub fn gen_y<W>(&self, out: &mut W) -> io::Result<()> where W: io::Write
3320	{	writeln!(out, "// Symbols:")?;
3321		let mut maxlen = 10;
3322		for sp in self.symbols.array[0 .. self.symbols.n_symbols].iter()
3323		{	if sp.name.len() > maxlen
3324			{	maxlen = sp.name.len();
3325			}
3326		}
3327		let mut ncolumns = 76 / (maxlen+5);
3328		if ncolumns < 1
3329		{	ncolumns = 1;
3330		}
3331		let skip = (self.symbols.n_symbols+ncolumns-1) / ncolumns;
3332		for i in 0 .. skip
3333		{	write!(out, "//")?;
3334			for j in (i .. self.symbols.n_symbols).step_by(skip)
3335			{	let sp = &self.symbols.array[j];
3336				assert_eq!(sp.index, j);
3337				write!(out, " {:3} {:<w$}", maxlen, sp.name, w=maxlen)?;
3338			}
3339			writeln!(out, "")?;
3340		}
3341		writeln!(out, "")?;
3342		// %start_symbol
3343		if !self.start_name.is_empty()
3344		{	writeln!(out, "%start_symbol {{{}}}", self.start_name)?;
3345		}
3346		// %token_type
3347		if !self.token_type.is_empty()
3348		{	writeln!(out, "%token_type {{{}}}", self.token_type)?;
3349		}
3350		// %default_type
3351		if !self.vartype.is_empty()
3352		{	writeln!(out, "%default_type {{{}}}", self.vartype)?;
3353		}
3354		// %extra_argument
3355		if !self.extra_argument_type.is_empty()
3356		{	writeln!(out, "%extra_argument {{{}}}", self.extra_argument_type)?;
3357		}
3358		// %left, %right, %nonassoc
3359		let mut prec = 0;
3360		loop
3361		{	let mut has_greater_prec = false;
3362			let mut started = false;
3363			for symbol in self.symbols.array[1 .. self.symbols.n_terminals].iter()
3364			{	if symbol.prec >= prec
3365				{	if symbol.prec > prec
3366					{	has_greater_prec = true;
3367					}
3368					else
3369					{	if !started
3370						{	write!(out, "{}", if symbol.assoc== Associativity::LEFT {"%left"} else if symbol.assoc== Associativity::RIGHT {"%right"} else {"%nonassoc"})?;
3371							started = true;
3372						}
3373						write!(out, " {}", symbol.name)?;
3374					}
3375				}
3376			}
3377			if started
3378			{	writeln!(out, ".")?;
3379			}
3380			if !has_greater_prec
3381			{	break;
3382			}
3383			prec += 1;
3384		}
3385		// %type
3386		for symbol in self.symbols.array[self.symbols.n_terminals+1 .. self.symbols.n_symbols].iter()
3387		{	let symbol = symbol;
3388			writeln!(out, "%type {} {{{}}}", symbol.name, symbol.data_type)?;
3389		}
3390		// rules
3391		for rule in self.rules.iter()
3392		{	write!(out, "{}", rule.lhs)?;
3393			if self.symbols.array[rule.lhs_index].dtnum != 0
3394			{	write!(out, "(RESULT)")?;
3395			}
3396			write!(out, " ::=")?;
3397			for sp in &rule.rhs
3398			{	write!(out, " {}", sp.name)?;
3399				if !sp.alias.is_empty()
3400				{	write!(out, "({})", sp.alias)?;
3401				}
3402			}
3403			write!(out, ".")?;
3404			if rule.precsym_index != std::usize::MAX
3405			{	write!(out, " [{}]", self.symbols.array[rule.precsym_index].name)?;
3406			}
3407			if !rule.code.is_empty()
3408			{	writeln!(out, " {{\n{}\n}}", rule.code)?;
3409			}
3410			writeln!(out, "")?;
3411		}
3412		Ok(())
3413	}
3414}
3415impl TryFrom<LemonMintBuilder> for LemonMint
3416{	type Error = LemonMintError;
3417
3418	fn try_from(builder: LemonMintBuilder) -> ParserResult<Self>
3419	{	builder.try_into_lemon()
3420	}
3421}
3422
3423#[cfg(not(feature = "with-debug"))]
3424fn dump_symbols(_symbols: &Symbols, _rules: &Vec<Rule>)
3425{
3426}
3427
3428#[cfg(not(feature = "with-debug"))]
3429fn dump_states(_states: &States, _rules: &Vec<Rule>, _symbols: &Symbols, _n: i32)
3430{
3431}
3432
3433#[cfg(feature = "with-debug")]
3434fn dump_symbols(symbols: &Symbols, rules: &Vec<Rule>)
3435{	use std::io::prelude::*;
3436	let mut out = File::create("/tmp/symbols-rust.js").unwrap();
3437	for s in symbols.array.iter()
3438	{	writeln!(out, "{} ({}) {:?} #{} {:?} {} {}LAM:", s.name, s.index, s.typ, s.dtnum, s.assoc, s.prec, if s.lambda {""} else {"!"}).unwrap();
3439		if s.firstset.len() > 0
3440		{	write!(out, "  ").unwrap();
3441			for (j, v) in s.firstset.data.iter().enumerate()
3442			{	write!(out, "{}{}", if j%4==0&&j>0 {" "} else {""}, if *v {'y'} else {'n'}).unwrap();
3443			}
3444			writeln!(out).unwrap();
3445		}
3446		for n_rule in s.sym_rules_arr.iter()
3447		{	let rule = &rules[*n_rule];
3448			writeln!(out, "   {} = {}", rule.index, rule.code).unwrap();
3449		}
3450	}
3451	/*	The same in lemon.c:
3452
3453		void dump_symbols(struct lemon *lemp)
3454		{	FILE *out = fopen("/tmp/symbols-c.js", "w");
3455			for (int i=0; i<lemp->nsymbol+1; i++)
3456			{	struct symbol *sym = lemp->symbols[i];
3457				fprintf(out, "%s (%d) %s #%d %s %d %s:\n", sym->name, sym->index, sym->type==TERMINAL?"TERMINAL":"NONTERMINAL", sym->dtnum, sym->assoc==LEFT?"LEFT":sym->assoc==RIGHT?"RIGHT":sym->assoc==NONE?"NONE":"UNKNOWN", sym->prec, sym->lambda?"LAM":"!LAM");
3458				if (sym->firstset)
3459				{	fprintf(out, "  ");
3460					for (int j=0; j<lemp->nterminal+1; j++)
3461					{	fprintf(out, "%s%c", j%4==0&&j>0 ? " " : "", sym->firstset[j]?'y':'n');
3462					}
3463					fprintf(out, "\n");
3464				}
3465				for (struct rule *rp=sym->rule; rp; rp=rp->nextlhs)
3466				{	const char *code = rp->code;
3467					if (code == nullptr) code = "";
3468					while (ISSPACE(code[0])) code++;
3469					int len = strlen(code);
3470					while (len>0 && ISSPACE(code[len-1])) len--;
3471					fprintf(out, "  %d = %.*s\n", rp->index, len, code);
3472				}
3473			}
3474			fclose(out);
3475		}
3476	*/
3477}
3478
3479#[cfg(feature = "with-debug")]
3480fn dump_states(states: &States, rules: &Vec<Rule>, symbols: &Symbols, n: i32)
3481{	use std::io::prelude::*;
3482	let mut out = File::create(format!("/tmp/states-{}-rust.js", n)).unwrap();
3483	for s in states.array.iter()
3484	{	writeln!
3485		(	out,
3486			"{}. nTknAct={}, nNtAct={}, iTknOfst={}, iNtOfst={}, iDfltReduce={}, {} dfR{}[{}]",
3487			s.n_state,
3488			s.n_token_act,
3489			s.n_nt_act,
3490			if s.token_offset==std::isize::MIN {-1000} else {s.token_offset},
3491			if s.nt_offset==std::isize::MIN {-1000} else {s.nt_offset},
3492			if s.default_reduce_action==std::usize::MAX {-1} else {s.default_reduce_action as isize},
3493			if s.auto_reduce {"A"} else {"!A"},
3494			if s.default_reduce_rule==std::usize::MAX {-1} else {s.default_reduce_rule as isize},
3495			if s.default_reduce_rule==std::usize::MAX {"".to_string()} else {rules[s.default_reduce_rule].lhs.to_string()}
3496		).unwrap();
3497		for cfp in s.basis.iter()
3498		{	let cfp = cfp.borrow();
3499			writeln!(out, "  bs{} R{}[{}] .{}", cfp.n_state as isize, cfp.n_rule, rules[cfp.n_rule].lhs, cfp.dot).unwrap();
3500		}
3501		for cfp in s.configurations.iter()
3502		{	let cfp = cfp.borrow();
3503			// rule
3504			writeln!(out, "  cf{} R{}[{}] .{}", cfp.n_state as isize, cfp.n_rule, rules[cfp.n_rule].lhs, cfp.dot).unwrap();
3505			// fws
3506			let mut delim = "";
3507			write!(out, "{:<12}[", "").unwrap();
3508			for (j, v) in cfp.fws.data.iter().enumerate()
3509			{	if *v
3510				{	write!(out, "{}{}", delim, symbols.array[j].name).unwrap();
3511					delim = " ";
3512				}
3513			}
3514			writeln!(out, "]").unwrap();
3515			// fplp
3516			for cfp in cfp.fplp.iter()
3517			{	write!(out, "{:<12}{} (state {:2}) ", "", "To  ", cfp.borrow().n_state as isize).unwrap();
3518				LemonMint::config_print(rules, &mut out, cfp).unwrap();
3519				writeln!(out).unwrap();
3520			}
3521			// bplp
3522			for cfp in cfp.bplp.iter()
3523			{	write!(out, "{:<12}{} (state {:2}) ", "", "From", cfp.borrow().n_state as isize).unwrap();
3524				LemonMint::config_print(rules, &mut out, cfp).unwrap();
3525				writeln!(out).unwrap();
3526			}
3527		}
3528		for action in s.actions.iter()
3529		{	if LemonMint::print_action(symbols, rules, action, &mut out, 30, true).unwrap()
3530			{	writeln!(out).unwrap();
3531			}
3532		}
3533	}
3534	/*	The same in lemon.c:
3535
3536		void dump_states(struct lemon *lemp, int n)
3537		{	char filename[1024];
3538			sprintf(filename, "/tmp/states-%d-c.js", n);
3539			FILE *out = fopen(filename, "w");
3540			showPrecedenceConflict = 1;
3541			for (int i=0; i<lemp->nstate; i++)
3542			{	struct state *stp = lemp->sorted[i];
3543				fprintf
3544				(	out,
3545					"%d. nTknAct=%d, nNtAct=%d, iTknOfst=%d, iNtOfst=%d, iDfltReduce=%d, %s dfR%d[%s]\n",
3546					stp->statenum,
3547					stp->nTknAct,
3548					stp->nNtAct,
3549					stp->iTknOfst==NO_OFFSET ? -1000 : stp->iTknOfst,
3550					stp->iNtOfst==NO_OFFSET ? -1000 : stp->iNtOfst,
3551					stp->iDfltReduce,
3552					stp->autoReduce?"A":"!A",
3553					stp->pDfltReduce ? stp->pDfltReduce->index : -1,
3554					stp->pDfltReduce ? stp->pDfltReduce->lhs->name : ""
3555				);
3556				for (struct config *cfp=stp->bp; cfp; cfp=cfp->bp)
3557				{	fprintf(out, "  bs%d R%d[%s] .%d\n", cfp->stp ? cfp->stp->statenum : -1, cfp->rp->index, cfp->rp->lhs->name, cfp->dot);
3558				}
3559				for (struct config *cfp=stp->cfp; cfp; cfp=cfp->next)
3560				{	fprintf(out, "  cf%d R%d[%s] .%d\n", cfp->stp ? cfp->stp->statenum : -1, cfp->rp->index, cfp->rp->lhs->name, cfp->dot);
3561					SetPrint(out, cfp->fws,lemp);
3562					PlinkPrint(out, cfp->fplp,"To  ");
3563					PlinkPrint(out, cfp->bplp,"From");
3564				}
3565				for (struct action *ap=stp->ap; ap; ap=ap->next)
3566				{	if (PrintAction(ap, out, 30)) fprintf(out, "\n");
3567				}
3568			}
3569			fclose(out);
3570		}
3571	*/
3572}