]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/bc/src/dc/lex.c
Update to version 3.1.1
[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 <status.h>
41 #include <lex.h>
42 #include <dc.h>
43 #include <vm.h>
44
45 bool dc_lex_negCommand(BcLex *l) {
46         char c = l->buf[l->i];
47         return !BC_LEX_NUM_CHAR(c, false, false);
48 }
49
50 static void dc_lex_register(BcLex *l) {
51
52         if (DC_X && isspace(l->buf[l->i - 1])) {
53
54                 char c;
55
56                 bc_lex_whitespace(l);
57                 c = l->buf[l->i];
58
59                 if (!isalnum(c) && c != '_')
60                         bc_lex_verr(l, BC_ERROR_PARSE_CHAR, c);
61
62                 l->i += 1;
63                 bc_lex_name(l);
64         }
65         else {
66                 bc_vec_npop(&l->str, l->str.len);
67                 bc_vec_pushByte(&l->str, (uchar) l->buf[l->i - 1]);
68                 bc_vec_pushByte(&l->str, '\0');
69                 l->t = BC_LEX_NAME;
70         }
71 }
72
73 static void dc_lex_string(BcLex *l) {
74
75         size_t depth = 1, nls = 0, i = l->i;
76         char c;
77
78         l->t = BC_LEX_STR;
79         bc_vec_npop(&l->str, l->str.len);
80
81         for (; (c = l->buf[i]) && depth; ++i) {
82
83                 if (c == '\\') {
84                         c = l->buf[++i];
85                         if (!c) break;
86                 }
87                 else {
88                         depth += (c == '[');
89                         depth -= (c == ']');
90                 }
91
92                 nls += (c == '\n');
93
94                 if (depth) bc_vec_push(&l->str, &c);
95         }
96
97         if (BC_ERR(c == '\0' && depth)) {
98                 l->i = i;
99                 bc_lex_err(l, BC_ERROR_PARSE_STRING);
100         }
101
102         bc_vec_pushByte(&l->str, '\0');
103
104         l->i = i;
105         l->line += nls;
106 }
107
108 void dc_lex_token(BcLex *l) {
109
110         char c = l->buf[l->i++], c2;
111         size_t i;
112
113         for (i = 0; i < dc_lex_regs_len; ++i) {
114                 if (l->last == dc_lex_regs[i]) {
115                         dc_lex_register(l);
116                         return;
117                 }
118         }
119
120         if (c >= '"' && c <= '~' &&
121             (l->t = dc_lex_tokens[(c - '"')]) != BC_LEX_INVALID)
122         {
123                 return;
124         }
125
126         // This is the workhorse of the lexer.
127         switch (c) {
128
129                 case '\0':
130                 case '\n':
131                 case '\t':
132                 case '\v':
133                 case '\f':
134                 case '\r':
135                 case ' ':
136                 {
137                         bc_lex_commonTokens(l, c);
138                         break;
139                 }
140
141                 case '!':
142                 {
143                         c2 = l->buf[l->i];
144
145                         if (c2 == '=') l->t = BC_LEX_OP_REL_NE;
146                         else if (c2 == '<') l->t = BC_LEX_OP_REL_LE;
147                         else if (c2 == '>') l->t = BC_LEX_OP_REL_GE;
148                         else bc_lex_invalidChar(l, c);
149
150                         l->i += 1;
151                         break;
152                 }
153
154                 case '#':
155                 {
156                         bc_lex_lineComment(l);
157                         break;
158                 }
159
160                 case '.':
161                 {
162                         c2 = l->buf[l->i];
163                         if (BC_NO_ERR(BC_LEX_NUM_CHAR(c2, true, false)))
164                                 bc_lex_number(l, c);
165                         else bc_lex_invalidChar(l, c);
166                         break;
167                 }
168
169                 case '0':
170                 case '1':
171                 case '2':
172                 case '3':
173                 case '4':
174                 case '5':
175                 case '6':
176                 case '7':
177                 case '8':
178                 case '9':
179                 case 'A':
180                 case 'B':
181                 case 'C':
182                 case 'D':
183                 case 'E':
184                 case 'F':
185                 {
186                         bc_lex_number(l, c);
187                         break;
188                 }
189
190                 case '[':
191                 {
192                         dc_lex_string(l);
193                         break;
194                 }
195
196                 default:
197                 {
198                         bc_lex_invalidChar(l, c);
199                 }
200         }
201 }
202 #endif // DC_ENABLED