xref: /freebsd/contrib/bc/include/lex.h (revision 78bc019d220e05abb5b12f678f9b4a847019bbcc)
1252884aeSStefan Eßer /*
2252884aeSStefan Eßer  * *****************************************************************************
3252884aeSStefan Eßer  *
43aa99676SStefan Eßer  * SPDX-License-Identifier: BSD-2-Clause
5252884aeSStefan Eßer  *
610328f8bSStefan Eßer  * Copyright (c) 2018-2021 Gavin D. Howard and contributors.
7252884aeSStefan Eßer  *
8252884aeSStefan Eßer  * Redistribution and use in source and binary forms, with or without
9252884aeSStefan Eßer  * modification, are permitted provided that the following conditions are met:
10252884aeSStefan Eßer  *
11252884aeSStefan Eßer  * * Redistributions of source code must retain the above copyright notice, this
12252884aeSStefan Eßer  *   list of conditions and the following disclaimer.
13252884aeSStefan Eßer  *
14252884aeSStefan Eßer  * * Redistributions in binary form must reproduce the above copyright notice,
15252884aeSStefan Eßer  *   this list of conditions and the following disclaimer in the documentation
16252884aeSStefan Eßer  *   and/or other materials provided with the distribution.
17252884aeSStefan Eßer  *
18252884aeSStefan Eßer  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19252884aeSStefan Eßer  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20252884aeSStefan Eßer  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21252884aeSStefan Eßer  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22252884aeSStefan Eßer  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23252884aeSStefan Eßer  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24252884aeSStefan Eßer  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25252884aeSStefan Eßer  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26252884aeSStefan Eßer  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27252884aeSStefan Eßer  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28252884aeSStefan Eßer  * POSSIBILITY OF SUCH DAMAGE.
29252884aeSStefan Eßer  *
30252884aeSStefan Eßer  * *****************************************************************************
31252884aeSStefan Eßer  *
32252884aeSStefan Eßer  * Definitions for bc's lexer.
33252884aeSStefan Eßer  *
34252884aeSStefan Eßer  */
35252884aeSStefan Eßer 
36252884aeSStefan Eßer #ifndef BC_LEX_H
37252884aeSStefan Eßer #define BC_LEX_H
38252884aeSStefan Eßer 
39252884aeSStefan Eßer #include <stdbool.h>
40252884aeSStefan Eßer #include <stddef.h>
41252884aeSStefan Eßer 
42252884aeSStefan Eßer #include <status.h>
43252884aeSStefan Eßer #include <vector.h>
44252884aeSStefan Eßer #include <lang.h>
45252884aeSStefan Eßer 
4644d4804dSStefan Eßer // Two convencience macros for throwing errors in lex code. They take care of
4744d4804dSStefan Eßer // plumbing like passing in the current line the lexer is on.
4850696a6eSStefan Eßer #define bc_lex_err(l, e) (bc_vm_handleError((e), (l)->line))
4950696a6eSStefan Eßer #define bc_lex_verr(l, e, ...) (bc_vm_handleError((e), (l)->line, __VA_ARGS__))
50252884aeSStefan Eßer 
5144d4804dSStefan Eßer // BC_LEX_NEG_CHAR returns the char that corresponds to negative for the
5244d4804dSStefan Eßer // current calculator.
5344d4804dSStefan Eßer //
5444d4804dSStefan Eßer // BC_LEX_LAST_NUM_CHAR returns the char that corresponds to the last valid
5544d4804dSStefan Eßer // char for numbers. In bc and dc, capital letters are part of numbers, to a
5644d4804dSStefan Eßer // point. (dc only goes up to hex, so its last valid char is 'F'.)
573aa99676SStefan Eßer #if BC_ENABLED
583aa99676SStefan Eßer 
593aa99676SStefan Eßer #if DC_ENABLED
60252884aeSStefan Eßer #define BC_LEX_NEG_CHAR (BC_IS_BC ? '-' : '_')
61252884aeSStefan Eßer #define BC_LEX_LAST_NUM_CHAR (BC_IS_BC ? 'Z' : 'F')
623aa99676SStefan Eßer #else // DC_ENABLED
633aa99676SStefan Eßer #define BC_LEX_NEG_CHAR ('-')
643aa99676SStefan Eßer #define BC_LEX_LAST_NUM_CHAR ('Z')
653aa99676SStefan Eßer #endif // DC_ENABLED
663aa99676SStefan Eßer 
673aa99676SStefan Eßer #else // BC_ENABLED
683aa99676SStefan Eßer 
693aa99676SStefan Eßer #define BC_LEX_NEG_CHAR ('_')
703aa99676SStefan Eßer #define BC_LEX_LAST_NUM_CHAR ('F')
713aa99676SStefan Eßer 
723aa99676SStefan Eßer #endif // BC_ENABLED
733aa99676SStefan Eßer 
7444d4804dSStefan Eßer /**
7544d4804dSStefan Eßer  * Returns true if c is a valid number character.
7644d4804dSStefan Eßer  * @param c         The char to check.
7744d4804dSStefan Eßer  * @param pt        If a decimal point has already been seen.
7844d4804dSStefan Eßer  * @param int_only  True if the number is expected to be an int only, false if
7944d4804dSStefan Eßer  *                  non-integers are allowed.
8044d4804dSStefan Eßer  * @return          True if @a c is a valid number character.
8144d4804dSStefan Eßer  */
82252884aeSStefan Eßer #define BC_LEX_NUM_CHAR(c, pt, int_only)                               \
8344d4804dSStefan Eßer 	(isdigit(c) != 0 || ((c) >= 'A' && (c) <= BC_LEX_LAST_NUM_CHAR) || \
84252884aeSStefan Eßer 	 ((c) == '.' && !(pt) && !(int_only)))
85252884aeSStefan Eßer 
8644d4804dSStefan Eßer /// An enum of lex token types.
87*78bc019dSStefan Eßer typedef enum BcLexType
88*78bc019dSStefan Eßer {
8944d4804dSStefan Eßer 	/// End of file.
90252884aeSStefan Eßer 	BC_LEX_EOF,
9144d4804dSStefan Eßer 
9244d4804dSStefan Eßer 	/// Marker for invalid tokens, used by bc and dc for const data.
93252884aeSStefan Eßer 	BC_LEX_INVALID,
94252884aeSStefan Eßer 
95252884aeSStefan Eßer #if BC_ENABLED
9644d4804dSStefan Eßer 
9744d4804dSStefan Eßer 	/// Increment operator.
98252884aeSStefan Eßer 	BC_LEX_OP_INC,
9944d4804dSStefan Eßer 
10044d4804dSStefan Eßer 	/// Decrement operator.
101252884aeSStefan Eßer 	BC_LEX_OP_DEC,
10244d4804dSStefan Eßer 
103252884aeSStefan Eßer #endif // BC_ENABLED
104252884aeSStefan Eßer 
10544d4804dSStefan Eßer 	/// BC_LEX_NEG is not used in lexing; it is only for parsing. The lexer
10644d4804dSStefan Eßer 	/// marks all '-' characters as BC_LEX_OP_MINUS, but the parser needs to be
10744d4804dSStefan Eßer 	/// able to distinguish them.
108252884aeSStefan Eßer 	BC_LEX_NEG,
10944d4804dSStefan Eßer 
11044d4804dSStefan Eßer 	/// Boolean not.
111252884aeSStefan Eßer 	BC_LEX_OP_BOOL_NOT,
11244d4804dSStefan Eßer 
113252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH
11444d4804dSStefan Eßer 
11544d4804dSStefan Eßer 	/// Truncation operator.
116252884aeSStefan Eßer 	BC_LEX_OP_TRUNC,
11744d4804dSStefan Eßer 
118252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
119252884aeSStefan Eßer 
12044d4804dSStefan Eßer 	/// Power operator.
121252884aeSStefan Eßer 	BC_LEX_OP_POWER,
12244d4804dSStefan Eßer 
12344d4804dSStefan Eßer 	/// Multiplication operator.
124252884aeSStefan Eßer 	BC_LEX_OP_MULTIPLY,
12544d4804dSStefan Eßer 
12644d4804dSStefan Eßer 	/// Division operator.
127252884aeSStefan Eßer 	BC_LEX_OP_DIVIDE,
12844d4804dSStefan Eßer 
12944d4804dSStefan Eßer 	/// Modulus operator.
130252884aeSStefan Eßer 	BC_LEX_OP_MODULUS,
13144d4804dSStefan Eßer 
13244d4804dSStefan Eßer 	/// Addition operator.
133252884aeSStefan Eßer 	BC_LEX_OP_PLUS,
13444d4804dSStefan Eßer 
13544d4804dSStefan Eßer 	/// Subtraction operator.
136252884aeSStefan Eßer 	BC_LEX_OP_MINUS,
137252884aeSStefan Eßer 
138252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH
13944d4804dSStefan Eßer 	/// Places (truncate or extend) operator.
140252884aeSStefan Eßer 	BC_LEX_OP_PLACES,
141252884aeSStefan Eßer 
14244d4804dSStefan Eßer 	/// Left (decimal) shift operator.
143252884aeSStefan Eßer 	BC_LEX_OP_LSHIFT,
14444d4804dSStefan Eßer 
14544d4804dSStefan Eßer 	/// Right (decimal) shift operator.
146252884aeSStefan Eßer 	BC_LEX_OP_RSHIFT,
147252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
148252884aeSStefan Eßer 
14944d4804dSStefan Eßer 	/// Equal operator.
150252884aeSStefan Eßer 	BC_LEX_OP_REL_EQ,
15144d4804dSStefan Eßer 
15244d4804dSStefan Eßer 	/// Less than or equal operator.
153252884aeSStefan Eßer 	BC_LEX_OP_REL_LE,
15444d4804dSStefan Eßer 
15544d4804dSStefan Eßer 	/// Greater than or equal operator.
156252884aeSStefan Eßer 	BC_LEX_OP_REL_GE,
15744d4804dSStefan Eßer 
15844d4804dSStefan Eßer 	/// Not equal operator.
159252884aeSStefan Eßer 	BC_LEX_OP_REL_NE,
16044d4804dSStefan Eßer 
16144d4804dSStefan Eßer 	/// Less than operator.
162252884aeSStefan Eßer 	BC_LEX_OP_REL_LT,
16344d4804dSStefan Eßer 
16444d4804dSStefan Eßer 	/// Greater than operator.
165252884aeSStefan Eßer 	BC_LEX_OP_REL_GT,
166252884aeSStefan Eßer 
16744d4804dSStefan Eßer 	/// Boolean or operator.
168252884aeSStefan Eßer 	BC_LEX_OP_BOOL_OR,
16944d4804dSStefan Eßer 
17044d4804dSStefan Eßer 	/// Boolean and operator.
171252884aeSStefan Eßer 	BC_LEX_OP_BOOL_AND,
172252884aeSStefan Eßer 
173252884aeSStefan Eßer #if BC_ENABLED
17444d4804dSStefan Eßer 	/// Power assignment operator.
175252884aeSStefan Eßer 	BC_LEX_OP_ASSIGN_POWER,
17644d4804dSStefan Eßer 
17744d4804dSStefan Eßer 	/// Multiplication assignment operator.
178252884aeSStefan Eßer 	BC_LEX_OP_ASSIGN_MULTIPLY,
17944d4804dSStefan Eßer 
18044d4804dSStefan Eßer 	/// Division assignment operator.
181252884aeSStefan Eßer 	BC_LEX_OP_ASSIGN_DIVIDE,
18244d4804dSStefan Eßer 
18344d4804dSStefan Eßer 	/// Modulus assignment operator.
184252884aeSStefan Eßer 	BC_LEX_OP_ASSIGN_MODULUS,
18544d4804dSStefan Eßer 
18644d4804dSStefan Eßer 	/// Addition assignment operator.
187252884aeSStefan Eßer 	BC_LEX_OP_ASSIGN_PLUS,
18844d4804dSStefan Eßer 
18944d4804dSStefan Eßer 	/// Subtraction assignment operator.
190252884aeSStefan Eßer 	BC_LEX_OP_ASSIGN_MINUS,
19144d4804dSStefan Eßer 
192252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH
19344d4804dSStefan Eßer 
19444d4804dSStefan Eßer 	/// Places (truncate or extend) assignment operator.
195252884aeSStefan Eßer 	BC_LEX_OP_ASSIGN_PLACES,
19644d4804dSStefan Eßer 
19744d4804dSStefan Eßer 	/// Left (decimal) shift assignment operator.
198252884aeSStefan Eßer 	BC_LEX_OP_ASSIGN_LSHIFT,
19944d4804dSStefan Eßer 
20044d4804dSStefan Eßer 	/// Right (decimal) shift assignment operator.
201252884aeSStefan Eßer 	BC_LEX_OP_ASSIGN_RSHIFT,
20244d4804dSStefan Eßer 
203252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
204252884aeSStefan Eßer #endif // BC_ENABLED
20544d4804dSStefan Eßer 
20644d4804dSStefan Eßer 	/// Assignment operator.
207252884aeSStefan Eßer 	BC_LEX_OP_ASSIGN,
208252884aeSStefan Eßer 
20944d4804dSStefan Eßer 	/// Newline.
210252884aeSStefan Eßer 	BC_LEX_NLINE,
21144d4804dSStefan Eßer 
21244d4804dSStefan Eßer 	/// Whitespace.
213252884aeSStefan Eßer 	BC_LEX_WHITESPACE,
214252884aeSStefan Eßer 
21544d4804dSStefan Eßer 	/// Left parenthesis.
216252884aeSStefan Eßer 	BC_LEX_LPAREN,
21744d4804dSStefan Eßer 
21844d4804dSStefan Eßer 	/// Right parenthesis.
219252884aeSStefan Eßer 	BC_LEX_RPAREN,
220252884aeSStefan Eßer 
22144d4804dSStefan Eßer 	/// Left bracket.
222252884aeSStefan Eßer 	BC_LEX_LBRACKET,
22344d4804dSStefan Eßer 
22444d4804dSStefan Eßer 	/// Comma.
225252884aeSStefan Eßer 	BC_LEX_COMMA,
22644d4804dSStefan Eßer 
22744d4804dSStefan Eßer 	/// Right bracket.
228252884aeSStefan Eßer 	BC_LEX_RBRACKET,
229252884aeSStefan Eßer 
23044d4804dSStefan Eßer 	/// Left brace.
231252884aeSStefan Eßer 	BC_LEX_LBRACE,
23244d4804dSStefan Eßer 
23344d4804dSStefan Eßer 	/// Semicolon.
234252884aeSStefan Eßer 	BC_LEX_SCOLON,
23544d4804dSStefan Eßer 
23644d4804dSStefan Eßer 	/// Right brace.
237252884aeSStefan Eßer 	BC_LEX_RBRACE,
238252884aeSStefan Eßer 
23944d4804dSStefan Eßer 	/// String.
240252884aeSStefan Eßer 	BC_LEX_STR,
24144d4804dSStefan Eßer 
24244d4804dSStefan Eßer 	/// Identifier/name.
243252884aeSStefan Eßer 	BC_LEX_NAME,
24444d4804dSStefan Eßer 
24544d4804dSStefan Eßer 	/// Constant number.
246252884aeSStefan Eßer 	BC_LEX_NUMBER,
247252884aeSStefan Eßer 
24844d4804dSStefan Eßer 	// These keywords are in the order they are in for a reason. Don't change
24944d4804dSStefan Eßer 	// the order unless you want a bunch of weird failures in the test suite.
25044d4804dSStefan Eßer 	// In fact, almost all of these tokens are in a specific order for a reason.
25144d4804dSStefan Eßer 
252252884aeSStefan Eßer #if BC_ENABLED
25344d4804dSStefan Eßer 
25444d4804dSStefan Eßer 	/// bc auto keyword.
255252884aeSStefan Eßer 	BC_LEX_KW_AUTO,
25644d4804dSStefan Eßer 
25744d4804dSStefan Eßer 	/// bc break keyword.
258252884aeSStefan Eßer 	BC_LEX_KW_BREAK,
25944d4804dSStefan Eßer 
26044d4804dSStefan Eßer 	/// bc continue keyword.
261252884aeSStefan Eßer 	BC_LEX_KW_CONTINUE,
26244d4804dSStefan Eßer 
26344d4804dSStefan Eßer 	/// bc define keyword.
264252884aeSStefan Eßer 	BC_LEX_KW_DEFINE,
26544d4804dSStefan Eßer 
26644d4804dSStefan Eßer 	/// bc for keyword.
267252884aeSStefan Eßer 	BC_LEX_KW_FOR,
26844d4804dSStefan Eßer 
26944d4804dSStefan Eßer 	/// bc if keyword.
270252884aeSStefan Eßer 	BC_LEX_KW_IF,
27144d4804dSStefan Eßer 
27244d4804dSStefan Eßer 	/// bc limits keyword.
273252884aeSStefan Eßer 	BC_LEX_KW_LIMITS,
27444d4804dSStefan Eßer 
27544d4804dSStefan Eßer 	/// bc return keyword.
276252884aeSStefan Eßer 	BC_LEX_KW_RETURN,
27744d4804dSStefan Eßer 
27844d4804dSStefan Eßer 	/// bc while keyword.
279252884aeSStefan Eßer 	BC_LEX_KW_WHILE,
28044d4804dSStefan Eßer 
28144d4804dSStefan Eßer 	/// bc halt keyword.
282252884aeSStefan Eßer 	BC_LEX_KW_HALT,
28344d4804dSStefan Eßer 
28444d4804dSStefan Eßer 	/// bc last keyword.
285252884aeSStefan Eßer 	BC_LEX_KW_LAST,
28644d4804dSStefan Eßer 
287252884aeSStefan Eßer #endif // BC_ENABLED
28844d4804dSStefan Eßer 
28944d4804dSStefan Eßer 	/// bc ibase keyword.
290252884aeSStefan Eßer 	BC_LEX_KW_IBASE,
29144d4804dSStefan Eßer 
29244d4804dSStefan Eßer 	/// bc obase keyword.
293252884aeSStefan Eßer 	BC_LEX_KW_OBASE,
29444d4804dSStefan Eßer 
29544d4804dSStefan Eßer 	/// bc scale keyword.
296252884aeSStefan Eßer 	BC_LEX_KW_SCALE,
29744d4804dSStefan Eßer 
29844d4804dSStefan Eßer #if BC_ENABLE_EXTRA_MATH
29944d4804dSStefan Eßer 
30044d4804dSStefan Eßer 	/// bc seed keyword.
301252884aeSStefan Eßer 	BC_LEX_KW_SEED,
30244d4804dSStefan Eßer 
30344d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
30444d4804dSStefan Eßer 
30544d4804dSStefan Eßer 	/// bc length keyword.
306252884aeSStefan Eßer 	BC_LEX_KW_LENGTH,
30744d4804dSStefan Eßer 
30844d4804dSStefan Eßer 	/// bc print keyword.
309252884aeSStefan Eßer 	BC_LEX_KW_PRINT,
31044d4804dSStefan Eßer 
31144d4804dSStefan Eßer 	/// bc sqrt keyword.
312252884aeSStefan Eßer 	BC_LEX_KW_SQRT,
31344d4804dSStefan Eßer 
31444d4804dSStefan Eßer 	/// bc abs keyword.
315252884aeSStefan Eßer 	BC_LEX_KW_ABS,
31644d4804dSStefan Eßer 
31744d4804dSStefan Eßer #if BC_ENABLE_EXTRA_MATH
31844d4804dSStefan Eßer 
31944d4804dSStefan Eßer 	/// bc irand keyword.
320252884aeSStefan Eßer 	BC_LEX_KW_IRAND,
32144d4804dSStefan Eßer 
32244d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
32344d4804dSStefan Eßer 
32444d4804dSStefan Eßer 	/// bc asciffy keyword.
32544d4804dSStefan Eßer 	BC_LEX_KW_ASCIIFY,
32644d4804dSStefan Eßer 
32744d4804dSStefan Eßer 	/// bc modexp keyword.
32844d4804dSStefan Eßer 	BC_LEX_KW_MODEXP,
32944d4804dSStefan Eßer 
33044d4804dSStefan Eßer 	/// bc divmod keyword.
33144d4804dSStefan Eßer 	BC_LEX_KW_DIVMOD,
33244d4804dSStefan Eßer 
33344d4804dSStefan Eßer 	/// bc quit keyword.
334252884aeSStefan Eßer 	BC_LEX_KW_QUIT,
33544d4804dSStefan Eßer 
33644d4804dSStefan Eßer 	/// bc read keyword.
337252884aeSStefan Eßer 	BC_LEX_KW_READ,
33844d4804dSStefan Eßer 
33944d4804dSStefan Eßer #if BC_ENABLE_EXTRA_MATH
34044d4804dSStefan Eßer 
34144d4804dSStefan Eßer 	/// bc rand keyword.
342252884aeSStefan Eßer 	BC_LEX_KW_RAND,
34344d4804dSStefan Eßer 
34444d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
34544d4804dSStefan Eßer 
34644d4804dSStefan Eßer 	/// bc maxibase keyword.
347252884aeSStefan Eßer 	BC_LEX_KW_MAXIBASE,
34844d4804dSStefan Eßer 
34944d4804dSStefan Eßer 	/// bc maxobase keyword.
350252884aeSStefan Eßer 	BC_LEX_KW_MAXOBASE,
35144d4804dSStefan Eßer 
35244d4804dSStefan Eßer 	/// bc maxscale keyword.
353252884aeSStefan Eßer 	BC_LEX_KW_MAXSCALE,
35444d4804dSStefan Eßer 
35544d4804dSStefan Eßer #if BC_ENABLE_EXTRA_MATH
35644d4804dSStefan Eßer 	/// bc maxrand keyword.
357252884aeSStefan Eßer 	BC_LEX_KW_MAXRAND,
35844d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
35944d4804dSStefan Eßer 
360d43fa8efSStefan Eßer 	/// bc line_length keyword.
361d43fa8efSStefan Eßer 	BC_LEX_KW_LINE_LENGTH,
362d43fa8efSStefan Eßer 
363d43fa8efSStefan Eßer #if BC_ENABLED
364d43fa8efSStefan Eßer 
365d43fa8efSStefan Eßer 	/// bc global_stacks keyword.
366d43fa8efSStefan Eßer 	BC_LEX_KW_GLOBAL_STACKS,
367d43fa8efSStefan Eßer 
368d43fa8efSStefan Eßer #endif // BC_ENABLED
369d43fa8efSStefan Eßer 
370d43fa8efSStefan Eßer 	/// bc leading_zero keyword.
371d43fa8efSStefan Eßer 	BC_LEX_KW_LEADING_ZERO,
372d43fa8efSStefan Eßer 
37344d4804dSStefan Eßer 	/// bc stream keyword.
37444d4804dSStefan Eßer 	BC_LEX_KW_STREAM,
37544d4804dSStefan Eßer 
37644d4804dSStefan Eßer 	/// bc else keyword.
377252884aeSStefan Eßer 	BC_LEX_KW_ELSE,
378252884aeSStefan Eßer 
379252884aeSStefan Eßer #if DC_ENABLED
380252884aeSStefan Eßer 
38144d4804dSStefan Eßer 	/// A special token for dc to calculate equal without a register.
38244d4804dSStefan Eßer 	BC_LEX_EQ_NO_REG,
38344d4804dSStefan Eßer 
38444d4804dSStefan Eßer 	/// Colon (array) operator.
385252884aeSStefan Eßer 	BC_LEX_COLON,
38644d4804dSStefan Eßer 
38744d4804dSStefan Eßer 	/// Execute command.
388252884aeSStefan Eßer 	BC_LEX_EXECUTE,
38944d4804dSStefan Eßer 
39044d4804dSStefan Eßer 	/// Print stack command.
391252884aeSStefan Eßer 	BC_LEX_PRINT_STACK,
39244d4804dSStefan Eßer 
39344d4804dSStefan Eßer 	/// Clear stack command.
394252884aeSStefan Eßer 	BC_LEX_CLEAR_STACK,
39544d4804dSStefan Eßer 
39644d4804dSStefan Eßer 	/// Register stack level command.
39744d4804dSStefan Eßer 	BC_LEX_REG_STACK_LEVEL,
39844d4804dSStefan Eßer 
39944d4804dSStefan Eßer 	/// Main stack level command.
400252884aeSStefan Eßer 	BC_LEX_STACK_LEVEL,
40144d4804dSStefan Eßer 
40244d4804dSStefan Eßer 	/// Duplicate command.
403252884aeSStefan Eßer 	BC_LEX_DUPLICATE,
40444d4804dSStefan Eßer 
40544d4804dSStefan Eßer 	/// Swap (reverse) command.
406252884aeSStefan Eßer 	BC_LEX_SWAP,
40744d4804dSStefan Eßer 
40844d4804dSStefan Eßer 	/// Pop (remove) command.
409252884aeSStefan Eßer 	BC_LEX_POP,
410252884aeSStefan Eßer 
41144d4804dSStefan Eßer 	/// Store ibase command.
412252884aeSStefan Eßer 	BC_LEX_STORE_IBASE,
41344d4804dSStefan Eßer 
41444d4804dSStefan Eßer 	/// Store obase command.
415252884aeSStefan Eßer 	BC_LEX_STORE_OBASE,
41644d4804dSStefan Eßer 
41744d4804dSStefan Eßer 	/// Store scale command.
418252884aeSStefan Eßer 	BC_LEX_STORE_SCALE,
41944d4804dSStefan Eßer 
420252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH
42144d4804dSStefan Eßer 	/// Store seed command.
422252884aeSStefan Eßer 	BC_LEX_STORE_SEED,
423252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
42444d4804dSStefan Eßer 
42544d4804dSStefan Eßer 	/// Load variable onto stack command.
426252884aeSStefan Eßer 	BC_LEX_LOAD,
42744d4804dSStefan Eßer 
42844d4804dSStefan Eßer 	/// Pop off of variable stack onto results stack command.
429252884aeSStefan Eßer 	BC_LEX_LOAD_POP,
43044d4804dSStefan Eßer 
43144d4804dSStefan Eßer 	/// Push onto variable stack command.
432252884aeSStefan Eßer 	BC_LEX_STORE_PUSH,
43344d4804dSStefan Eßer 
43444d4804dSStefan Eßer 	/// Print with pop command.
435252884aeSStefan Eßer 	BC_LEX_PRINT_POP,
43644d4804dSStefan Eßer 
43744d4804dSStefan Eßer 	/// Parameterized quit command.
438252884aeSStefan Eßer 	BC_LEX_NQUIT,
43944d4804dSStefan Eßer 
44044d4804dSStefan Eßer 	/// Execution stack depth command.
44144d4804dSStefan Eßer 	BC_LEX_EXEC_STACK_LENGTH,
44244d4804dSStefan Eßer 
44344d4804dSStefan Eßer 	/// Scale of number command. This is needed specifically for dc because bc
44444d4804dSStefan Eßer 	/// parses the scale function in parts.
445252884aeSStefan Eßer 	BC_LEX_SCALE_FACTOR,
44644d4804dSStefan Eßer 
44744d4804dSStefan Eßer 	/// Array length command. This is needed specifically for dc because bc
44844d4804dSStefan Eßer 	/// just reuses its length keyword.
44944d4804dSStefan Eßer 	BC_LEX_ARRAY_LENGTH,
45044d4804dSStefan Eßer 
451252884aeSStefan Eßer #endif // DC_ENABLED
452252884aeSStefan Eßer 
453252884aeSStefan Eßer } BcLexType;
454252884aeSStefan Eßer 
455252884aeSStefan Eßer struct BcLex;
456252884aeSStefan Eßer 
45744d4804dSStefan Eßer /**
45844d4804dSStefan Eßer  * A function pointer to call when another token is needed. Mostly called by the
45944d4804dSStefan Eßer  * parser.
46044d4804dSStefan Eßer  * @param l  The lexer.
46144d4804dSStefan Eßer  */
46244d4804dSStefan Eßer typedef void (*BcLexNext)(struct BcLex* l);
46344d4804dSStefan Eßer 
46444d4804dSStefan Eßer /// The lexer.
465*78bc019dSStefan Eßer typedef struct BcLex
466*78bc019dSStefan Eßer {
46744d4804dSStefan Eßer 	/// A pointer to the text to lex.
468252884aeSStefan Eßer 	const char* buf;
46944d4804dSStefan Eßer 
47044d4804dSStefan Eßer 	/// The current index into buf.
471252884aeSStefan Eßer 	size_t i;
47244d4804dSStefan Eßer 
47344d4804dSStefan Eßer 	/// The current line.
474252884aeSStefan Eßer 	size_t line;
47544d4804dSStefan Eßer 
47644d4804dSStefan Eßer 	/// The length of buf.
477252884aeSStefan Eßer 	size_t len;
478252884aeSStefan Eßer 
47944d4804dSStefan Eßer 	/// The current token.
480252884aeSStefan Eßer 	BcLexType t;
48144d4804dSStefan Eßer 
48244d4804dSStefan Eßer 	/// The previous token.
483252884aeSStefan Eßer 	BcLexType last;
48444d4804dSStefan Eßer 
48544d4804dSStefan Eßer 	/// A string to store extra data for tokens. For example, the @a BC_LEX_STR
48644d4804dSStefan Eßer 	/// token really needs to store the actual string, and numbers also need the
48744d4804dSStefan Eßer 	/// string.
488252884aeSStefan Eßer 	BcVec str;
489252884aeSStefan Eßer 
49044d4804dSStefan Eßer 	/// If this is true, the lexer is processing stdin and can ask for more data
49144d4804dSStefan Eßer 	/// if a string or comment are not properly terminated.
49244d4804dSStefan Eßer 	bool is_stdin;
49344d4804dSStefan Eßer 
49423210c9fSStefan Eßer 	/// If this is true, the lexer is processing expressions from the
49523210c9fSStefan Eßer 	/// command-line and can ask for more data if a string or comment are not
49623210c9fSStefan Eßer 	/// properly terminated.
49723210c9fSStefan Eßer 	bool is_exprs;
49823210c9fSStefan Eßer 
499252884aeSStefan Eßer } BcLex;
500252884aeSStefan Eßer 
50144d4804dSStefan Eßer /**
50244d4804dSStefan Eßer  * Initializes a lexer.
50344d4804dSStefan Eßer  * @param l  The lexer to initialize.
50444d4804dSStefan Eßer  */
505*78bc019dSStefan Eßer void
506*78bc019dSStefan Eßer bc_lex_init(BcLex* l);
50744d4804dSStefan Eßer 
50844d4804dSStefan Eßer /**
50944d4804dSStefan Eßer  * Frees a lexer. This is not guarded by #ifndef NDEBUG because a separate
51044d4804dSStefan Eßer  * parser is created at runtime to parse read() expressions and dc strings, and
51144d4804dSStefan Eßer  * that parser needs a lexer.
51244d4804dSStefan Eßer  * @param l  The lexer to free.
51344d4804dSStefan Eßer  */
514*78bc019dSStefan Eßer void
515*78bc019dSStefan Eßer bc_lex_free(BcLex* l);
51644d4804dSStefan Eßer 
51744d4804dSStefan Eßer /**
51844d4804dSStefan Eßer  * Sets the filename that the lexer will be lexing.
51944d4804dSStefan Eßer  * @param l     The lexer.
52044d4804dSStefan Eßer  * @param file  The filename that the lexer will lex.
52144d4804dSStefan Eßer  */
522*78bc019dSStefan Eßer void
523*78bc019dSStefan Eßer bc_lex_file(BcLex* l, const char* file);
52444d4804dSStefan Eßer 
52544d4804dSStefan Eßer /**
52644d4804dSStefan Eßer  * Sets the text the lexer will lex.
52744d4804dSStefan Eßer  * @param l         The lexer.
52844d4804dSStefan Eßer  * @param text      The text to lex.
52944d4804dSStefan Eßer  * @param is_stdin  True if the text is from stdin, false otherwise.
53023210c9fSStefan Eßer  * @param is_exprs  True if the text is from command-line expressions, false
53123210c9fSStefan Eßer  *                  otherwise.
53244d4804dSStefan Eßer  */
533*78bc019dSStefan Eßer void
534*78bc019dSStefan Eßer bc_lex_text(BcLex* l, const char* text, bool is_stdin, bool is_exprs);
53544d4804dSStefan Eßer 
53644d4804dSStefan Eßer /**
53744d4804dSStefan Eßer  * Generic next function for the parser to call. It takes care of calling the
53844d4804dSStefan Eßer  * correct @a BcLexNext function and consuming whitespace.
53944d4804dSStefan Eßer  * @param l  The lexer.
54044d4804dSStefan Eßer  */
541*78bc019dSStefan Eßer void
542*78bc019dSStefan Eßer bc_lex_next(BcLex* l);
543252884aeSStefan Eßer 
54444d4804dSStefan Eßer /**
54544d4804dSStefan Eßer  * Lexes a line comment (one beginning with '#' and going to a newline).
54644d4804dSStefan Eßer  * @param l  The lexer.
54744d4804dSStefan Eßer  */
548*78bc019dSStefan Eßer void
549*78bc019dSStefan Eßer bc_lex_lineComment(BcLex* l);
55044d4804dSStefan Eßer 
55144d4804dSStefan Eßer /**
55244d4804dSStefan Eßer  * Lexes a general comment (C-style comment).
55344d4804dSStefan Eßer  * @param l  The lexer.
55444d4804dSStefan Eßer  */
555*78bc019dSStefan Eßer void
556*78bc019dSStefan Eßer bc_lex_comment(BcLex* l);
55744d4804dSStefan Eßer 
55844d4804dSStefan Eßer /**
55944d4804dSStefan Eßer  * Lexes whitespace, finding as much as possible.
56044d4804dSStefan Eßer  * @param l  The lexer.
56144d4804dSStefan Eßer  */
562*78bc019dSStefan Eßer void
563*78bc019dSStefan Eßer bc_lex_whitespace(BcLex* l);
56444d4804dSStefan Eßer 
56544d4804dSStefan Eßer /**
56644d4804dSStefan Eßer  * Lexes a number that begins with char @a start. This takes care of parsing
56744d4804dSStefan Eßer  * numbers in scientific and engineering notations.
56844d4804dSStefan Eßer  * @param l      The lexer.
56944d4804dSStefan Eßer  * @param start  The starting char of the number. To detect a number and call
57044d4804dSStefan Eßer  *               this function, the lexer had to eat the first char. It fixes
57144d4804dSStefan Eßer  *               that by passing it in.
57244d4804dSStefan Eßer  */
573*78bc019dSStefan Eßer void
574*78bc019dSStefan Eßer bc_lex_number(BcLex* l, char start);
57544d4804dSStefan Eßer 
57644d4804dSStefan Eßer /**
57744d4804dSStefan Eßer  * Lexes a name/identifier.
57844d4804dSStefan Eßer  * @param l  The lexer.
57944d4804dSStefan Eßer  */
580*78bc019dSStefan Eßer void
581*78bc019dSStefan Eßer bc_lex_name(BcLex* l);
58244d4804dSStefan Eßer 
58344d4804dSStefan Eßer /**
58444d4804dSStefan Eßer  * Lexes common whitespace characters.
58544d4804dSStefan Eßer  * @param l  The lexer.
58644d4804dSStefan Eßer  * @param c  The character to lex.
58744d4804dSStefan Eßer  */
588*78bc019dSStefan Eßer void
589*78bc019dSStefan Eßer bc_lex_commonTokens(BcLex* l, char c);
590252884aeSStefan Eßer 
59144d4804dSStefan Eßer /**
59244d4804dSStefan Eßer  * Throws a parse error because char @a c was invalid.
59344d4804dSStefan Eßer  * @param l  The lexer.
59444d4804dSStefan Eßer  * @param c  The problem character.
59544d4804dSStefan Eßer  */
596*78bc019dSStefan Eßer void
597*78bc019dSStefan Eßer bc_lex_invalidChar(BcLex* l, char c);
598252884aeSStefan Eßer 
59944d4804dSStefan Eßer /**
60044d4804dSStefan Eßer  * Reads a line from stdin and puts it into the lexer's buffer.
60144d4804dSStefan Eßer  * @param l  The lexer.
60244d4804dSStefan Eßer  */
603*78bc019dSStefan Eßer bool
604*78bc019dSStefan Eßer bc_lex_readLine(BcLex* l);
60544d4804dSStefan Eßer 
606252884aeSStefan Eßer #endif // BC_LEX_H
607