]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - src/dc_parse.c
Import version 3.2.0
[FreeBSD/FreeBSD.git] / src / dc_parse.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 parser for dc.
33  *
34  */
35
36 #if DC_ENABLED
37
38 #include <assert.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <setjmp.h>
42
43 #include <dc.h>
44 #include <program.h>
45 #include <vm.h>
46
47 static void dc_parse_register(BcParse *p, bool var) {
48
49         bc_lex_next(&p->l);
50         if (p->l.t != BC_LEX_NAME) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
51
52         bc_parse_pushName(p, p->l.str.v, var);
53 }
54
55 static inline void dc_parse_string(BcParse *p) {
56         bc_parse_addString(p);
57         bc_lex_next(&p->l);
58 }
59
60 static void dc_parse_mem(BcParse *p, uchar inst, bool name, bool store) {
61
62         bc_parse_push(p, inst);
63
64         if (name) dc_parse_register(p, inst != BC_INST_ARRAY_ELEM);
65
66         if (store) {
67                 bc_parse_push(p, BC_INST_SWAP);
68                 bc_parse_push(p, BC_INST_ASSIGN_NO_VAL);
69         }
70
71         bc_lex_next(&p->l);
72 }
73
74 static void dc_parse_cond(BcParse *p, uchar inst) {
75
76         bc_parse_push(p, inst);
77         bc_parse_push(p, BC_INST_EXEC_COND);
78
79         dc_parse_register(p, true);
80
81         bc_lex_next(&p->l);
82
83         if (p->l.t == BC_LEX_KW_ELSE) {
84                 dc_parse_register(p, true);
85                 bc_lex_next(&p->l);
86         }
87         else bc_parse_pushIndex(p, SIZE_MAX);
88 }
89
90 static void dc_parse_token(BcParse *p, BcLexType t, uint8_t flags) {
91
92         uchar inst;
93         bool assign, get_token = false;
94
95         switch (t) {
96
97                 case BC_LEX_OP_REL_EQ:
98                 case BC_LEX_OP_REL_LE:
99                 case BC_LEX_OP_REL_GE:
100                 case BC_LEX_OP_REL_NE:
101                 case BC_LEX_OP_REL_LT:
102                 case BC_LEX_OP_REL_GT:
103                 {
104                         inst = (uchar) (t - BC_LEX_OP_REL_EQ + BC_INST_REL_EQ);
105                         dc_parse_cond(p, inst);
106                         break;
107                 }
108
109                 case BC_LEX_SCOLON:
110                 case BC_LEX_COLON:
111                 {
112                         dc_parse_mem(p, BC_INST_ARRAY_ELEM, true, t == BC_LEX_COLON);
113                         break;
114                 }
115
116                 case BC_LEX_STR:
117                 {
118                         dc_parse_string(p);
119                         break;
120                 }
121
122                 case BC_LEX_NEG:
123                 {
124                         if (dc_lex_negCommand(&p->l)) {
125                                 bc_parse_push(p, BC_INST_NEG);
126                                 get_token = true;
127                                 break;
128                         }
129
130                         bc_lex_next(&p->l);
131                 }
132                 // Fallthrough.
133                 BC_FALLTHROUGH
134
135                 case BC_LEX_NUMBER:
136                 {
137                         bc_parse_number(p);
138
139                         if (t == BC_LEX_NEG) bc_parse_push(p, BC_INST_NEG);
140                         get_token = true;
141
142                         break;
143                 }
144
145                 case BC_LEX_KW_READ:
146                 {
147                         if (BC_ERR(flags & BC_PARSE_NOREAD))
148                                 bc_parse_err(p, BC_ERR_EXEC_REC_READ);
149                         else bc_parse_push(p, BC_INST_READ);
150                         get_token = true;
151                         break;
152                 }
153
154                 case BC_LEX_OP_ASSIGN:
155                 case BC_LEX_STORE_PUSH:
156                 {
157                         assign = t == BC_LEX_OP_ASSIGN;
158                         inst = assign ? BC_INST_VAR : BC_INST_PUSH_TO_VAR;
159                         dc_parse_mem(p, inst, true, assign);
160                         break;
161                 }
162
163                 case BC_LEX_LOAD:
164                 case BC_LEX_LOAD_POP:
165                 {
166                         inst = t == BC_LEX_LOAD_POP ? BC_INST_PUSH_VAR : BC_INST_LOAD;
167                         dc_parse_mem(p, inst, true, false);
168                         break;
169                 }
170
171                 case BC_LEX_STORE_IBASE:
172                 case BC_LEX_STORE_OBASE:
173                 case BC_LEX_STORE_SCALE:
174 #if BC_ENABLE_EXTRA_MATH
175                 case BC_LEX_STORE_SEED:
176 #endif // BC_ENABLE_EXTRA_MATH
177                 {
178                         inst = (uchar) (t - BC_LEX_STORE_IBASE + BC_INST_IBASE);
179                         dc_parse_mem(p, inst, false, true);
180                         break;
181                 }
182
183                 default:
184                 {
185                         bc_parse_err(p, BC_ERR_PARSE_TOKEN);
186                 }
187         }
188
189         if (get_token) bc_lex_next(&p->l);
190 }
191
192 void dc_parse_expr(BcParse *p, uint8_t flags) {
193
194         BcInst inst;
195         BcLexType t;
196         bool have_expr = false, need_expr = (flags & BC_PARSE_NOREAD) != 0;
197
198         while ((t = p->l.t) != BC_LEX_EOF) {
199
200                 if (t == BC_LEX_NLINE) {
201                         bc_lex_next(&p->l);
202                         continue;
203                 }
204
205                 inst = dc_parse_insts[t];
206
207                 if (inst != BC_INST_INVALID) {
208                         bc_parse_push(p, inst);
209                         bc_lex_next(&p->l);
210                 }
211                 else dc_parse_token(p, t, flags);
212
213                 have_expr = true;
214         }
215
216         if (BC_ERR(need_expr && !have_expr))
217                 bc_vm_err(BC_ERR_EXEC_READ_EXPR);
218         else if (p->l.t == BC_LEX_EOF && (flags & BC_PARSE_NOCALL))
219                 bc_parse_push(p, BC_INST_POP_EXEC);
220 }
221
222 void dc_parse_parse(BcParse *p) {
223
224         assert(p != NULL);
225
226         BC_SETJMP(exit);
227
228         if (BC_ERR(p->l.t == BC_LEX_EOF)) bc_parse_err(p, BC_ERR_PARSE_EOF);
229         else dc_parse_expr(p, 0);
230
231 exit:
232         BC_SIG_MAYLOCK;
233         if (BC_ERR(vm.status || vm.sig)) bc_parse_reset(p);
234         BC_LONGJMP_CONT;
235 }
236 #endif // DC_ENABLED