xref: /freebsd/contrib/bc/include/lex.h (revision a970610a3af63b3f4df5b69d91c6b4093a00ed8f)
1252884aeSStefan Eßer /*
2252884aeSStefan Eßer  * *****************************************************************************
3252884aeSStefan Eßer  *
43aa99676SStefan Eßer  * SPDX-License-Identifier: BSD-2-Clause
5252884aeSStefan Eßer  *
6*a970610aSStefan Eßer  * Copyright (c) 2018-2024 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 
46d101cdd6SStefan Eßer /**
47d101cdd6SStefan Eßer  * A convenience macro for throwing errors in lex code. This takes care of
48d101cdd6SStefan Eßer  * plumbing like passing in the current line the lexer is on.
49d101cdd6SStefan Eßer  * @param l  The lexer.
50d101cdd6SStefan Eßer  * @param e  The error.
51d101cdd6SStefan Eßer  */
52103d7cdfSStefan Eßer #if BC_DEBUG
53d101cdd6SStefan Eßer #define bc_lex_err(l, e) (bc_vm_handleError((e), __FILE__, __LINE__, (l)->line))
54103d7cdfSStefan Eßer #else // BC_DEBUG
5550696a6eSStefan Eßer #define bc_lex_err(l, e) (bc_vm_handleError((e), (l)->line))
56103d7cdfSStefan Eßer #endif // BC_DEBUG
57d101cdd6SStefan Eßer 
58d101cdd6SStefan Eßer /**
59d101cdd6SStefan Eßer  * A convenience macro for throwing errors in lex code. This takes care of
60d101cdd6SStefan Eßer  * plumbing like passing in the current line the lexer is on.
61d101cdd6SStefan Eßer  * @param l  The lexer.
62d101cdd6SStefan Eßer  * @param e  The error.
63d101cdd6SStefan Eßer  */
64103d7cdfSStefan Eßer #if BC_DEBUG
65d101cdd6SStefan Eßer #define bc_lex_verr(l, e, ...) \
66d101cdd6SStefan Eßer 	(bc_vm_handleError((e), __FILE__, __LINE__, (l)->line, __VA_ARGS__))
67103d7cdfSStefan Eßer #else // BC_DEBUG
6850696a6eSStefan Eßer #define bc_lex_verr(l, e, ...) (bc_vm_handleError((e), (l)->line, __VA_ARGS__))
69103d7cdfSStefan Eßer #endif // BC_DEBUG
70252884aeSStefan Eßer 
7144d4804dSStefan Eßer // BC_LEX_NEG_CHAR returns the char that corresponds to negative for the
7244d4804dSStefan Eßer // current calculator.
7344d4804dSStefan Eßer //
7444d4804dSStefan Eßer // BC_LEX_LAST_NUM_CHAR returns the char that corresponds to the last valid
7544d4804dSStefan Eßer // char for numbers. In bc and dc, capital letters are part of numbers, to a
7644d4804dSStefan Eßer // point. (dc only goes up to hex, so its last valid char is 'F'.)
773aa99676SStefan Eßer #if BC_ENABLED
783aa99676SStefan Eßer 
793aa99676SStefan Eßer #if DC_ENABLED
80252884aeSStefan Eßer #define BC_LEX_NEG_CHAR (BC_IS_BC ? '-' : '_')
81252884aeSStefan Eßer #define BC_LEX_LAST_NUM_CHAR (BC_IS_BC ? 'Z' : 'F')
823aa99676SStefan Eßer #else // DC_ENABLED
833aa99676SStefan Eßer #define BC_LEX_NEG_CHAR ('-')
843aa99676SStefan Eßer #define BC_LEX_LAST_NUM_CHAR ('Z')
853aa99676SStefan Eßer #endif // DC_ENABLED
863aa99676SStefan Eßer 
873aa99676SStefan Eßer #else // BC_ENABLED
883aa99676SStefan Eßer 
893aa99676SStefan Eßer #define BC_LEX_NEG_CHAR ('_')
903aa99676SStefan Eßer #define BC_LEX_LAST_NUM_CHAR ('F')
913aa99676SStefan Eßer 
923aa99676SStefan Eßer #endif // BC_ENABLED
933aa99676SStefan Eßer 
9444d4804dSStefan Eßer /**
9544d4804dSStefan Eßer  * Returns true if c is a valid number character.
9644d4804dSStefan Eßer  * @param c         The char to check.
9744d4804dSStefan Eßer  * @param pt        If a decimal point has already been seen.
9844d4804dSStefan Eßer  * @param int_only  True if the number is expected to be an int only, false if
9944d4804dSStefan Eßer  *                  non-integers are allowed.
10044d4804dSStefan Eßer  * @return          True if @a c is a valid number character.
10144d4804dSStefan Eßer  */
102252884aeSStefan Eßer #define BC_LEX_NUM_CHAR(c, pt, int_only)                               \
10344d4804dSStefan Eßer 	(isdigit(c) != 0 || ((c) >= 'A' && (c) <= BC_LEX_LAST_NUM_CHAR) || \
104252884aeSStefan Eßer 	 ((c) == '.' && !(pt) && !(int_only)))
105252884aeSStefan Eßer 
10644d4804dSStefan Eßer /// An enum of lex token types.
10778bc019dSStefan Eßer typedef enum BcLexType
10878bc019dSStefan Eßer {
10944d4804dSStefan Eßer 	/// End of file.
110252884aeSStefan Eßer 	BC_LEX_EOF,
11144d4804dSStefan Eßer 
11244d4804dSStefan Eßer 	/// Marker for invalid tokens, used by bc and dc for const data.
113252884aeSStefan Eßer 	BC_LEX_INVALID,
114252884aeSStefan Eßer 
115252884aeSStefan Eßer #if BC_ENABLED
11644d4804dSStefan Eßer 
11744d4804dSStefan Eßer 	/// Increment operator.
118252884aeSStefan Eßer 	BC_LEX_OP_INC,
11944d4804dSStefan Eßer 
12044d4804dSStefan Eßer 	/// Decrement operator.
121252884aeSStefan Eßer 	BC_LEX_OP_DEC,
12244d4804dSStefan Eßer 
123252884aeSStefan Eßer #endif // BC_ENABLED
124252884aeSStefan Eßer 
12544d4804dSStefan Eßer 	/// BC_LEX_NEG is not used in lexing; it is only for parsing. The lexer
12644d4804dSStefan Eßer 	/// marks all '-' characters as BC_LEX_OP_MINUS, but the parser needs to be
12744d4804dSStefan Eßer 	/// able to distinguish them.
128252884aeSStefan Eßer 	BC_LEX_NEG,
12944d4804dSStefan Eßer 
13044d4804dSStefan Eßer 	/// Boolean not.
131252884aeSStefan Eßer 	BC_LEX_OP_BOOL_NOT,
13244d4804dSStefan Eßer 
133252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH
13444d4804dSStefan Eßer 
13544d4804dSStefan Eßer 	/// Truncation operator.
136252884aeSStefan Eßer 	BC_LEX_OP_TRUNC,
13744d4804dSStefan Eßer 
138252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
139252884aeSStefan Eßer 
14044d4804dSStefan Eßer 	/// Power operator.
141252884aeSStefan Eßer 	BC_LEX_OP_POWER,
14244d4804dSStefan Eßer 
14344d4804dSStefan Eßer 	/// Multiplication operator.
144252884aeSStefan Eßer 	BC_LEX_OP_MULTIPLY,
14544d4804dSStefan Eßer 
14644d4804dSStefan Eßer 	/// Division operator.
147252884aeSStefan Eßer 	BC_LEX_OP_DIVIDE,
14844d4804dSStefan Eßer 
14944d4804dSStefan Eßer 	/// Modulus operator.
150252884aeSStefan Eßer 	BC_LEX_OP_MODULUS,
15144d4804dSStefan Eßer 
15244d4804dSStefan Eßer 	/// Addition operator.
153252884aeSStefan Eßer 	BC_LEX_OP_PLUS,
15444d4804dSStefan Eßer 
15544d4804dSStefan Eßer 	/// Subtraction operator.
156252884aeSStefan Eßer 	BC_LEX_OP_MINUS,
157252884aeSStefan Eßer 
158252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH
159d101cdd6SStefan Eßer 
16044d4804dSStefan Eßer 	/// Places (truncate or extend) operator.
161252884aeSStefan Eßer 	BC_LEX_OP_PLACES,
162252884aeSStefan Eßer 
16344d4804dSStefan Eßer 	/// Left (decimal) shift operator.
164252884aeSStefan Eßer 	BC_LEX_OP_LSHIFT,
16544d4804dSStefan Eßer 
16644d4804dSStefan Eßer 	/// Right (decimal) shift operator.
167252884aeSStefan Eßer 	BC_LEX_OP_RSHIFT,
168d101cdd6SStefan Eßer 
169252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
170252884aeSStefan Eßer 
17144d4804dSStefan Eßer 	/// Equal operator.
172252884aeSStefan Eßer 	BC_LEX_OP_REL_EQ,
17344d4804dSStefan Eßer 
17444d4804dSStefan Eßer 	/// Less than or equal operator.
175252884aeSStefan Eßer 	BC_LEX_OP_REL_LE,
17644d4804dSStefan Eßer 
17744d4804dSStefan Eßer 	/// Greater than or equal operator.
178252884aeSStefan Eßer 	BC_LEX_OP_REL_GE,
17944d4804dSStefan Eßer 
18044d4804dSStefan Eßer 	/// Not equal operator.
181252884aeSStefan Eßer 	BC_LEX_OP_REL_NE,
18244d4804dSStefan Eßer 
18344d4804dSStefan Eßer 	/// Less than operator.
184252884aeSStefan Eßer 	BC_LEX_OP_REL_LT,
18544d4804dSStefan Eßer 
18644d4804dSStefan Eßer 	/// Greater than operator.
187252884aeSStefan Eßer 	BC_LEX_OP_REL_GT,
188252884aeSStefan Eßer 
18944d4804dSStefan Eßer 	/// Boolean or operator.
190252884aeSStefan Eßer 	BC_LEX_OP_BOOL_OR,
19144d4804dSStefan Eßer 
19244d4804dSStefan Eßer 	/// Boolean and operator.
193252884aeSStefan Eßer 	BC_LEX_OP_BOOL_AND,
194252884aeSStefan Eßer 
195252884aeSStefan Eßer #if BC_ENABLED
196d101cdd6SStefan Eßer 
19744d4804dSStefan Eßer 	/// Power assignment operator.
198252884aeSStefan Eßer 	BC_LEX_OP_ASSIGN_POWER,
19944d4804dSStefan Eßer 
20044d4804dSStefan Eßer 	/// Multiplication assignment operator.
201252884aeSStefan Eßer 	BC_LEX_OP_ASSIGN_MULTIPLY,
20244d4804dSStefan Eßer 
20344d4804dSStefan Eßer 	/// Division assignment operator.
204252884aeSStefan Eßer 	BC_LEX_OP_ASSIGN_DIVIDE,
20544d4804dSStefan Eßer 
20644d4804dSStefan Eßer 	/// Modulus assignment operator.
207252884aeSStefan Eßer 	BC_LEX_OP_ASSIGN_MODULUS,
20844d4804dSStefan Eßer 
20944d4804dSStefan Eßer 	/// Addition assignment operator.
210252884aeSStefan Eßer 	BC_LEX_OP_ASSIGN_PLUS,
21144d4804dSStefan Eßer 
21244d4804dSStefan Eßer 	/// Subtraction assignment operator.
213252884aeSStefan Eßer 	BC_LEX_OP_ASSIGN_MINUS,
21444d4804dSStefan Eßer 
215252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH
21644d4804dSStefan Eßer 
21744d4804dSStefan Eßer 	/// Places (truncate or extend) assignment operator.
218252884aeSStefan Eßer 	BC_LEX_OP_ASSIGN_PLACES,
21944d4804dSStefan Eßer 
22044d4804dSStefan Eßer 	/// Left (decimal) shift assignment operator.
221252884aeSStefan Eßer 	BC_LEX_OP_ASSIGN_LSHIFT,
22244d4804dSStefan Eßer 
22344d4804dSStefan Eßer 	/// Right (decimal) shift assignment operator.
224252884aeSStefan Eßer 	BC_LEX_OP_ASSIGN_RSHIFT,
22544d4804dSStefan Eßer 
226252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
227252884aeSStefan Eßer #endif // BC_ENABLED
22844d4804dSStefan Eßer 
22944d4804dSStefan Eßer 	/// Assignment operator.
230252884aeSStefan Eßer 	BC_LEX_OP_ASSIGN,
231252884aeSStefan Eßer 
23244d4804dSStefan Eßer 	/// Newline.
233252884aeSStefan Eßer 	BC_LEX_NLINE,
23444d4804dSStefan Eßer 
23544d4804dSStefan Eßer 	/// Whitespace.
236252884aeSStefan Eßer 	BC_LEX_WHITESPACE,
237252884aeSStefan Eßer 
23844d4804dSStefan Eßer 	/// Left parenthesis.
239252884aeSStefan Eßer 	BC_LEX_LPAREN,
24044d4804dSStefan Eßer 
24144d4804dSStefan Eßer 	/// Right parenthesis.
242252884aeSStefan Eßer 	BC_LEX_RPAREN,
243252884aeSStefan Eßer 
24444d4804dSStefan Eßer 	/// Left bracket.
245252884aeSStefan Eßer 	BC_LEX_LBRACKET,
24644d4804dSStefan Eßer 
24744d4804dSStefan Eßer 	/// Comma.
248252884aeSStefan Eßer 	BC_LEX_COMMA,
24944d4804dSStefan Eßer 
25044d4804dSStefan Eßer 	/// Right bracket.
251252884aeSStefan Eßer 	BC_LEX_RBRACKET,
252252884aeSStefan Eßer 
25344d4804dSStefan Eßer 	/// Left brace.
254252884aeSStefan Eßer 	BC_LEX_LBRACE,
25544d4804dSStefan Eßer 
25644d4804dSStefan Eßer 	/// Semicolon.
257252884aeSStefan Eßer 	BC_LEX_SCOLON,
25844d4804dSStefan Eßer 
25944d4804dSStefan Eßer 	/// Right brace.
260252884aeSStefan Eßer 	BC_LEX_RBRACE,
261252884aeSStefan Eßer 
26244d4804dSStefan Eßer 	/// String.
263252884aeSStefan Eßer 	BC_LEX_STR,
26444d4804dSStefan Eßer 
26544d4804dSStefan Eßer 	/// Identifier/name.
266252884aeSStefan Eßer 	BC_LEX_NAME,
26744d4804dSStefan Eßer 
26844d4804dSStefan Eßer 	/// Constant number.
269252884aeSStefan Eßer 	BC_LEX_NUMBER,
270252884aeSStefan Eßer 
27144d4804dSStefan Eßer 	// These keywords are in the order they are in for a reason. Don't change
27244d4804dSStefan Eßer 	// the order unless you want a bunch of weird failures in the test suite.
27344d4804dSStefan Eßer 	// In fact, almost all of these tokens are in a specific order for a reason.
27444d4804dSStefan Eßer 
275252884aeSStefan Eßer #if BC_ENABLED
27644d4804dSStefan Eßer 
27744d4804dSStefan Eßer 	/// bc auto keyword.
278252884aeSStefan Eßer 	BC_LEX_KW_AUTO,
27944d4804dSStefan Eßer 
28044d4804dSStefan Eßer 	/// bc break keyword.
281252884aeSStefan Eßer 	BC_LEX_KW_BREAK,
28244d4804dSStefan Eßer 
28344d4804dSStefan Eßer 	/// bc continue keyword.
284252884aeSStefan Eßer 	BC_LEX_KW_CONTINUE,
28544d4804dSStefan Eßer 
28644d4804dSStefan Eßer 	/// bc define keyword.
287252884aeSStefan Eßer 	BC_LEX_KW_DEFINE,
28844d4804dSStefan Eßer 
28944d4804dSStefan Eßer 	/// bc for keyword.
290252884aeSStefan Eßer 	BC_LEX_KW_FOR,
29144d4804dSStefan Eßer 
29244d4804dSStefan Eßer 	/// bc if keyword.
293252884aeSStefan Eßer 	BC_LEX_KW_IF,
29444d4804dSStefan Eßer 
29544d4804dSStefan Eßer 	/// bc limits keyword.
296252884aeSStefan Eßer 	BC_LEX_KW_LIMITS,
29744d4804dSStefan Eßer 
29844d4804dSStefan Eßer 	/// bc return keyword.
299252884aeSStefan Eßer 	BC_LEX_KW_RETURN,
30044d4804dSStefan Eßer 
30144d4804dSStefan Eßer 	/// bc while keyword.
302252884aeSStefan Eßer 	BC_LEX_KW_WHILE,
30344d4804dSStefan Eßer 
30444d4804dSStefan Eßer 	/// bc halt keyword.
305252884aeSStefan Eßer 	BC_LEX_KW_HALT,
30644d4804dSStefan Eßer 
30744d4804dSStefan Eßer 	/// bc last keyword.
308252884aeSStefan Eßer 	BC_LEX_KW_LAST,
30944d4804dSStefan Eßer 
310252884aeSStefan Eßer #endif // BC_ENABLED
31144d4804dSStefan Eßer 
31244d4804dSStefan Eßer 	/// bc ibase keyword.
313252884aeSStefan Eßer 	BC_LEX_KW_IBASE,
31444d4804dSStefan Eßer 
31544d4804dSStefan Eßer 	/// bc obase keyword.
316252884aeSStefan Eßer 	BC_LEX_KW_OBASE,
31744d4804dSStefan Eßer 
31844d4804dSStefan Eßer 	/// bc scale keyword.
319252884aeSStefan Eßer 	BC_LEX_KW_SCALE,
32044d4804dSStefan Eßer 
32144d4804dSStefan Eßer #if BC_ENABLE_EXTRA_MATH
32244d4804dSStefan Eßer 
32344d4804dSStefan Eßer 	/// bc seed keyword.
324252884aeSStefan Eßer 	BC_LEX_KW_SEED,
32544d4804dSStefan Eßer 
32644d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
32744d4804dSStefan Eßer 
32844d4804dSStefan Eßer 	/// bc length keyword.
329252884aeSStefan Eßer 	BC_LEX_KW_LENGTH,
33044d4804dSStefan Eßer 
33144d4804dSStefan Eßer 	/// bc print keyword.
332252884aeSStefan Eßer 	BC_LEX_KW_PRINT,
33344d4804dSStefan Eßer 
33444d4804dSStefan Eßer 	/// bc sqrt keyword.
335252884aeSStefan Eßer 	BC_LEX_KW_SQRT,
33644d4804dSStefan Eßer 
33744d4804dSStefan Eßer 	/// bc abs keyword.
338252884aeSStefan Eßer 	BC_LEX_KW_ABS,
33944d4804dSStefan Eßer 
340d101cdd6SStefan Eßer 	/// bc is_number keyword.
341d101cdd6SStefan Eßer 	BC_LEX_KW_IS_NUMBER,
342d101cdd6SStefan Eßer 
343d101cdd6SStefan Eßer 	/// bc is_string keyword.
344d101cdd6SStefan Eßer 	BC_LEX_KW_IS_STRING,
345d101cdd6SStefan Eßer 
34644d4804dSStefan Eßer #if BC_ENABLE_EXTRA_MATH
34744d4804dSStefan Eßer 
34844d4804dSStefan Eßer 	/// bc irand keyword.
349252884aeSStefan Eßer 	BC_LEX_KW_IRAND,
35044d4804dSStefan Eßer 
35144d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
35244d4804dSStefan Eßer 
35344d4804dSStefan Eßer 	/// bc asciffy keyword.
35444d4804dSStefan Eßer 	BC_LEX_KW_ASCIIFY,
35544d4804dSStefan Eßer 
35644d4804dSStefan Eßer 	/// bc modexp keyword.
35744d4804dSStefan Eßer 	BC_LEX_KW_MODEXP,
35844d4804dSStefan Eßer 
35944d4804dSStefan Eßer 	/// bc divmod keyword.
36044d4804dSStefan Eßer 	BC_LEX_KW_DIVMOD,
36144d4804dSStefan Eßer 
36244d4804dSStefan Eßer 	/// bc quit keyword.
363252884aeSStefan Eßer 	BC_LEX_KW_QUIT,
36444d4804dSStefan Eßer 
36544d4804dSStefan Eßer 	/// bc read keyword.
366252884aeSStefan Eßer 	BC_LEX_KW_READ,
36744d4804dSStefan Eßer 
36844d4804dSStefan Eßer #if BC_ENABLE_EXTRA_MATH
36944d4804dSStefan Eßer 
37044d4804dSStefan Eßer 	/// bc rand keyword.
371252884aeSStefan Eßer 	BC_LEX_KW_RAND,
37244d4804dSStefan Eßer 
37344d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
37444d4804dSStefan Eßer 
37544d4804dSStefan Eßer 	/// bc maxibase keyword.
376252884aeSStefan Eßer 	BC_LEX_KW_MAXIBASE,
37744d4804dSStefan Eßer 
37844d4804dSStefan Eßer 	/// bc maxobase keyword.
379252884aeSStefan Eßer 	BC_LEX_KW_MAXOBASE,
38044d4804dSStefan Eßer 
38144d4804dSStefan Eßer 	/// bc maxscale keyword.
382252884aeSStefan Eßer 	BC_LEX_KW_MAXSCALE,
38344d4804dSStefan Eßer 
38444d4804dSStefan Eßer #if BC_ENABLE_EXTRA_MATH
385d101cdd6SStefan Eßer 
38644d4804dSStefan Eßer 	/// bc maxrand keyword.
387252884aeSStefan Eßer 	BC_LEX_KW_MAXRAND,
388d101cdd6SStefan Eßer 
38944d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
39044d4804dSStefan Eßer 
391d43fa8efSStefan Eßer 	/// bc line_length keyword.
392d43fa8efSStefan Eßer 	BC_LEX_KW_LINE_LENGTH,
393d43fa8efSStefan Eßer 
394d43fa8efSStefan Eßer #if BC_ENABLED
395d43fa8efSStefan Eßer 
396d43fa8efSStefan Eßer 	/// bc global_stacks keyword.
397d43fa8efSStefan Eßer 	BC_LEX_KW_GLOBAL_STACKS,
398d43fa8efSStefan Eßer 
399d43fa8efSStefan Eßer #endif // BC_ENABLED
400d43fa8efSStefan Eßer 
401d43fa8efSStefan Eßer 	/// bc leading_zero keyword.
402d43fa8efSStefan Eßer 	BC_LEX_KW_LEADING_ZERO,
403d43fa8efSStefan Eßer 
40444d4804dSStefan Eßer 	/// bc stream keyword.
40544d4804dSStefan Eßer 	BC_LEX_KW_STREAM,
40644d4804dSStefan Eßer 
40744d4804dSStefan Eßer 	/// bc else keyword.
408252884aeSStefan Eßer 	BC_LEX_KW_ELSE,
409252884aeSStefan Eßer 
410252884aeSStefan Eßer #if DC_ENABLED
411252884aeSStefan Eßer 
412103d7cdfSStefan Eßer 	/// dc extended registers keyword.
413103d7cdfSStefan Eßer 	BC_LEX_EXTENDED_REGISTERS,
414103d7cdfSStefan Eßer 
41544d4804dSStefan Eßer 	/// A special token for dc to calculate equal without a register.
41644d4804dSStefan Eßer 	BC_LEX_EQ_NO_REG,
41744d4804dSStefan Eßer 
41844d4804dSStefan Eßer 	/// Colon (array) operator.
419252884aeSStefan Eßer 	BC_LEX_COLON,
42044d4804dSStefan Eßer 
42144d4804dSStefan Eßer 	/// Execute command.
422252884aeSStefan Eßer 	BC_LEX_EXECUTE,
42344d4804dSStefan Eßer 
42444d4804dSStefan Eßer 	/// Print stack command.
425252884aeSStefan Eßer 	BC_LEX_PRINT_STACK,
42644d4804dSStefan Eßer 
42744d4804dSStefan Eßer 	/// Clear stack command.
428252884aeSStefan Eßer 	BC_LEX_CLEAR_STACK,
42944d4804dSStefan Eßer 
43044d4804dSStefan Eßer 	/// Register stack level command.
43144d4804dSStefan Eßer 	BC_LEX_REG_STACK_LEVEL,
43244d4804dSStefan Eßer 
43344d4804dSStefan Eßer 	/// Main stack level command.
434252884aeSStefan Eßer 	BC_LEX_STACK_LEVEL,
43544d4804dSStefan Eßer 
43644d4804dSStefan Eßer 	/// Duplicate command.
437252884aeSStefan Eßer 	BC_LEX_DUPLICATE,
43844d4804dSStefan Eßer 
43944d4804dSStefan Eßer 	/// Swap (reverse) command.
440252884aeSStefan Eßer 	BC_LEX_SWAP,
44144d4804dSStefan Eßer 
44244d4804dSStefan Eßer 	/// Pop (remove) command.
443252884aeSStefan Eßer 	BC_LEX_POP,
444252884aeSStefan Eßer 
44544d4804dSStefan Eßer 	/// Store ibase command.
446252884aeSStefan Eßer 	BC_LEX_STORE_IBASE,
44744d4804dSStefan Eßer 
44844d4804dSStefan Eßer 	/// Store obase command.
449252884aeSStefan Eßer 	BC_LEX_STORE_OBASE,
45044d4804dSStefan Eßer 
45144d4804dSStefan Eßer 	/// Store scale command.
452252884aeSStefan Eßer 	BC_LEX_STORE_SCALE,
45344d4804dSStefan Eßer 
454252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH
455d101cdd6SStefan Eßer 
45644d4804dSStefan Eßer 	/// Store seed command.
457252884aeSStefan Eßer 	BC_LEX_STORE_SEED,
458d101cdd6SStefan Eßer 
459252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
46044d4804dSStefan Eßer 
46144d4804dSStefan Eßer 	/// Load variable onto stack command.
462252884aeSStefan Eßer 	BC_LEX_LOAD,
46344d4804dSStefan Eßer 
46444d4804dSStefan Eßer 	/// Pop off of variable stack onto results stack command.
465252884aeSStefan Eßer 	BC_LEX_LOAD_POP,
46644d4804dSStefan Eßer 
46744d4804dSStefan Eßer 	/// Push onto variable stack command.
468252884aeSStefan Eßer 	BC_LEX_STORE_PUSH,
46944d4804dSStefan Eßer 
47044d4804dSStefan Eßer 	/// Print with pop command.
471252884aeSStefan Eßer 	BC_LEX_PRINT_POP,
47244d4804dSStefan Eßer 
47344d4804dSStefan Eßer 	/// Parameterized quit command.
474252884aeSStefan Eßer 	BC_LEX_NQUIT,
47544d4804dSStefan Eßer 
47644d4804dSStefan Eßer 	/// Execution stack depth command.
47744d4804dSStefan Eßer 	BC_LEX_EXEC_STACK_LENGTH,
47844d4804dSStefan Eßer 
47944d4804dSStefan Eßer 	/// Scale of number command. This is needed specifically for dc because bc
48044d4804dSStefan Eßer 	/// parses the scale function in parts.
481252884aeSStefan Eßer 	BC_LEX_SCALE_FACTOR,
48244d4804dSStefan Eßer 
48344d4804dSStefan Eßer 	/// Array length command. This is needed specifically for dc because bc
48444d4804dSStefan Eßer 	/// just reuses its length keyword.
48544d4804dSStefan Eßer 	BC_LEX_ARRAY_LENGTH,
48644d4804dSStefan Eßer 
487252884aeSStefan Eßer #endif // DC_ENABLED
488252884aeSStefan Eßer 
489252884aeSStefan Eßer } BcLexType;
490252884aeSStefan Eßer 
491252884aeSStefan Eßer struct BcLex;
492252884aeSStefan Eßer 
49344d4804dSStefan Eßer /**
49444d4804dSStefan Eßer  * A function pointer to call when another token is needed. Mostly called by the
49544d4804dSStefan Eßer  * parser.
49644d4804dSStefan Eßer  * @param l  The lexer.
49744d4804dSStefan Eßer  */
49844d4804dSStefan Eßer typedef void (*BcLexNext)(struct BcLex* l);
49944d4804dSStefan Eßer 
50044d4804dSStefan Eßer /// The lexer.
50178bc019dSStefan Eßer typedef struct BcLex
50278bc019dSStefan Eßer {
50344d4804dSStefan Eßer 	/// A pointer to the text to lex.
504252884aeSStefan Eßer 	const char* buf;
50544d4804dSStefan Eßer 
50644d4804dSStefan Eßer 	/// The current index into buf.
507252884aeSStefan Eßer 	size_t i;
50844d4804dSStefan Eßer 
50944d4804dSStefan Eßer 	/// The current line.
510252884aeSStefan Eßer 	size_t line;
51144d4804dSStefan Eßer 
51244d4804dSStefan Eßer 	/// The length of buf.
513252884aeSStefan Eßer 	size_t len;
514252884aeSStefan Eßer 
51544d4804dSStefan Eßer 	/// The current token.
516252884aeSStefan Eßer 	BcLexType t;
51744d4804dSStefan Eßer 
51844d4804dSStefan Eßer 	/// The previous token.
519252884aeSStefan Eßer 	BcLexType last;
52044d4804dSStefan Eßer 
52144d4804dSStefan Eßer 	/// A string to store extra data for tokens. For example, the @a BC_LEX_STR
52244d4804dSStefan Eßer 	/// token really needs to store the actual string, and numbers also need the
52344d4804dSStefan Eßer 	/// string.
524252884aeSStefan Eßer 	BcVec str;
525252884aeSStefan Eßer 
526d101cdd6SStefan Eßer 	/// The mode the lexer is in.
527d101cdd6SStefan Eßer 	BcMode mode;
52823210c9fSStefan Eßer 
529252884aeSStefan Eßer } BcLex;
530252884aeSStefan Eßer 
53144d4804dSStefan Eßer /**
53244d4804dSStefan Eßer  * Initializes a lexer.
53344d4804dSStefan Eßer  * @param l  The lexer to initialize.
53444d4804dSStefan Eßer  */
53578bc019dSStefan Eßer void
53678bc019dSStefan Eßer bc_lex_init(BcLex* l);
53744d4804dSStefan Eßer 
53844d4804dSStefan Eßer /**
539103d7cdfSStefan Eßer  * Frees a lexer. This is not guarded by #if BC_DEBUG because a separate
54044d4804dSStefan Eßer  * parser is created at runtime to parse read() expressions and dc strings, and
54144d4804dSStefan Eßer  * that parser needs a lexer.
54244d4804dSStefan Eßer  * @param l  The lexer to free.
54344d4804dSStefan Eßer  */
54478bc019dSStefan Eßer void
54578bc019dSStefan Eßer bc_lex_free(BcLex* l);
54644d4804dSStefan Eßer 
54744d4804dSStefan Eßer /**
54844d4804dSStefan Eßer  * Sets the filename that the lexer will be lexing.
54944d4804dSStefan Eßer  * @param l     The lexer.
55044d4804dSStefan Eßer  * @param file  The filename that the lexer will lex.
55144d4804dSStefan Eßer  */
55278bc019dSStefan Eßer void
55378bc019dSStefan Eßer bc_lex_file(BcLex* l, const char* file);
55444d4804dSStefan Eßer 
55544d4804dSStefan Eßer /**
55644d4804dSStefan Eßer  * Sets the text the lexer will lex.
55744d4804dSStefan Eßer  * @param l     The lexer.
55844d4804dSStefan Eßer  * @param text  The text to lex.
559d101cdd6SStefan Eßer  * @param mode  The mode to lex in.
56044d4804dSStefan Eßer  */
56178bc019dSStefan Eßer void
562d101cdd6SStefan Eßer bc_lex_text(BcLex* l, const char* text, BcMode mode);
56344d4804dSStefan Eßer 
56444d4804dSStefan Eßer /**
56544d4804dSStefan Eßer  * Generic next function for the parser to call. It takes care of calling the
56644d4804dSStefan Eßer  * correct @a BcLexNext function and consuming whitespace.
56744d4804dSStefan Eßer  * @param l  The lexer.
56844d4804dSStefan Eßer  */
56978bc019dSStefan Eßer void
57078bc019dSStefan Eßer bc_lex_next(BcLex* l);
571252884aeSStefan Eßer 
57244d4804dSStefan Eßer /**
57344d4804dSStefan Eßer  * Lexes a line comment (one beginning with '#' and going to a newline).
57444d4804dSStefan Eßer  * @param l  The lexer.
57544d4804dSStefan Eßer  */
57678bc019dSStefan Eßer void
57778bc019dSStefan Eßer bc_lex_lineComment(BcLex* l);
57844d4804dSStefan Eßer 
57944d4804dSStefan Eßer /**
58044d4804dSStefan Eßer  * Lexes a general comment (C-style comment).
58144d4804dSStefan Eßer  * @param l  The lexer.
58244d4804dSStefan Eßer  */
58378bc019dSStefan Eßer void
58478bc019dSStefan Eßer bc_lex_comment(BcLex* l);
58544d4804dSStefan Eßer 
58644d4804dSStefan Eßer /**
58744d4804dSStefan Eßer  * Lexes whitespace, finding as much as possible.
58844d4804dSStefan Eßer  * @param l  The lexer.
58944d4804dSStefan Eßer  */
59078bc019dSStefan Eßer void
59178bc019dSStefan Eßer bc_lex_whitespace(BcLex* l);
59244d4804dSStefan Eßer 
59344d4804dSStefan Eßer /**
59444d4804dSStefan Eßer  * Lexes a number that begins with char @a start. This takes care of parsing
59544d4804dSStefan Eßer  * numbers in scientific and engineering notations.
59644d4804dSStefan Eßer  * @param l      The lexer.
59744d4804dSStefan Eßer  * @param start  The starting char of the number. To detect a number and call
59844d4804dSStefan Eßer  *               this function, the lexer had to eat the first char. It fixes
59944d4804dSStefan Eßer  *               that by passing it in.
60044d4804dSStefan Eßer  */
60178bc019dSStefan Eßer void
60278bc019dSStefan Eßer bc_lex_number(BcLex* l, char start);
60344d4804dSStefan Eßer 
60444d4804dSStefan Eßer /**
60544d4804dSStefan Eßer  * Lexes a name/identifier.
60644d4804dSStefan Eßer  * @param l  The lexer.
60744d4804dSStefan Eßer  */
60878bc019dSStefan Eßer void
60978bc019dSStefan Eßer bc_lex_name(BcLex* l);
61044d4804dSStefan Eßer 
61144d4804dSStefan Eßer /**
61244d4804dSStefan Eßer  * Lexes common whitespace characters.
61344d4804dSStefan Eßer  * @param l  The lexer.
61444d4804dSStefan Eßer  * @param c  The character to lex.
61544d4804dSStefan Eßer  */
61678bc019dSStefan Eßer void
61778bc019dSStefan Eßer bc_lex_commonTokens(BcLex* l, char c);
618252884aeSStefan Eßer 
61944d4804dSStefan Eßer /**
62044d4804dSStefan Eßer  * Throws a parse error because char @a c was invalid.
62144d4804dSStefan Eßer  * @param l  The lexer.
62244d4804dSStefan Eßer  * @param c  The problem character.
62344d4804dSStefan Eßer  */
62478bc019dSStefan Eßer void
62578bc019dSStefan Eßer bc_lex_invalidChar(BcLex* l, char c);
626252884aeSStefan Eßer 
62744d4804dSStefan Eßer /**
62844d4804dSStefan Eßer  * Reads a line from stdin and puts it into the lexer's buffer.
62944d4804dSStefan Eßer  * @param l  The lexer.
63044d4804dSStefan Eßer  */
63178bc019dSStefan Eßer bool
63278bc019dSStefan Eßer bc_lex_readLine(BcLex* l);
63344d4804dSStefan Eßer 
634252884aeSStefan Eßer #endif // BC_LEX_H
635