]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/bc/src/dc_lex.c
Update to version 3.2.0
[FreeBSD/FreeBSD.git] / contrib / bc / src / dc_lex.c
1 /*
2  * *****************************************************************************
3  *
4  * SPDX-License-Identifier: BSD-2-Clause
5  *
6  * Copyright (c) 2018-2020 Gavin D. Howard and contributors.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are met:
10  *
11  * * Redistributions of source code must retain the above copyright notice, this
12  *   list of conditions and the following disclaimer.
13  *
14  * * Redistributions in binary form must reproduce the above copyright notice,
15  *   this list of conditions and the following disclaimer in the documentation
16  *   and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  *
30  * *****************************************************************************
31  *
32  * The lexer for dc.
33  *
34  */
35
36 #if DC_ENABLED
37
38 #include <ctype.h>
39
40 #include <dc.h>
41 #include <vm.h>
42
43 bool dc_lex_negCommand(BcLex *l) {
44         char c = l->buf[l->i];
45         return !BC_LEX_NUM_CHAR(c, false, false);
46 }
47
48 static void dc_lex_register(BcLex *l) {
49
50         if (DC_X && isspace(l->buf[l->i - 1])) {
51
52                 char c;
53
54                 bc_lex_whitespace(l);
55                 c = l->buf[l->i];
56
57                 if (!isalnum(c) && c != '_')
58                         bc_lex_verr(l, BC_ERR_PARSE_CHAR, c);
59
60                 l->i += 1;
61                 bc_lex_name(l);
62         }
63         else {
64                 bc_vec_npop(&l->str, l->str.len);
65                 bc_vec_pushByte(&l->str, (uchar) l->buf[l->i - 1]);
66                 bc_vec_pushByte(&l->str, '\0');
67                 l->t = BC_LEX_NAME;
68         }
69 }
70
71 static void dc_lex_string(BcLex *l) {
72
73         size_t depth = 1, nls = 0, i = l->i;
74         char c;
75
76         l->t = BC_LEX_STR;
77         bc_vec_npop(&l->str, l->str.len);
78
79         for (; (c = l->buf[i]) && depth; ++i) {
80
81                 if (c == '\\') {
82                         c = l->buf[++i];
83                         if (!c) break;
84                 }
85                 else {
86                         depth += (c == '[');
87                         depth -= (c == ']');
88                 }
89
90                 nls += (c == '\n');
91
92                 if (depth) bc_vec_push(&l->str, &c);
93         }
94
95         if (BC_ERR(c == '\0' && depth)) {
96                 l->i = i;
97                 bc_lex_err(l, BC_ERR_PARSE_STRING);
98         }
99
100         bc_vec_pushByte(&l->str, '\0');
101
102         l->i = i;
103         l->line += nls;
104 }
105
106 void dc_lex_token(BcLex *l) {
107
108         char c = l->buf[l->i++], c2;
109         size_t i;
110
111         for (i = 0; i < dc_lex_regs_len; ++i) {
112                 if (l->last == dc_lex_regs[i]) {
113                         dc_lex_register(l);
114                         return;
115                 }
116         }
117
118         if (c >= '"' && c <= '~' &&
119             (l->t = dc_lex_tokens[(c - '"')]) != BC_LEX_INVALID)
120         {
121                 return;
122         }
123
124         // This is the workhorse of the lexer.
125         switch (c) {
126
127                 case '\0':
128                 case '\n':
129                 case '\t':
130                 case '\v':
131                 case '\f':
132                 case '\r':
133                 case ' ':
134                 {
135                         bc_lex_commonTokens(l, c);
136                         break;
137                 }
138
139                 case '!':
140                 {
141                         c2 = l->buf[l->i];
142
143                         if (c2 == '=') l->t = BC_LEX_OP_REL_NE;
144                         else if (c2 == '<') l->t = BC_LEX_OP_REL_LE;
145                         else if (c2 == '>') l->t = BC_LEX_OP_REL_GE;
146                         else bc_lex_invalidChar(l, c);
147
148                         l->i += 1;
149                         break;
150                 }
151
152                 case '#':
153                 {
154                         bc_lex_lineComment(l);
155                         break;
156                 }
157
158                 case '.':
159                 {
160                         c2 = l->buf[l->i];
161                         if (BC_NO_ERR(BC_LEX_NUM_CHAR(c2, true, false)))
162                                 bc_lex_number(l, c);
163                         else bc_lex_invalidChar(l, c);
164                         break;
165                 }
166
167                 case '0':
168                 case '1':
169                 case '2':
170                 case '3':
171                 case '4':
172                 case '5':
173                 case '6':
174                 case '7':
175                 case '8':
176                 case '9':
177                 case 'A':
178                 case 'B':
179                 case 'C':
180                 case 'D':
181                 case 'E':
182                 case 'F':
183                 {
184                         bc_lex_number(l, c);
185                         break;
186                 }
187
188                 case '[':
189                 {
190                         dc_lex_string(l);
191                         break;
192                 }
193
194                 default:
195                 {
196                         bc_lex_invalidChar(l, c);
197                 }
198         }
199 }
200 #endif // DC_ENABLED