parser-brackets.c
1 //! @file parser-brackets.c
2 //! @author J. Marcel van der Veer
3 //!
4 //! @section Copyright
5 //!
6 //! This file is part of Algol68G - an Algol 68 compiler-interpreter.
7 //! Copyright 2001-2023 J. Marcel van der Veer [algol68g@xs4all.nl].
8 //!
9 //! @section License
10 //!
11 //! This program is free software; you can redistribute it and/or modify it
12 //! under the terms of the GNU General Public License as published by the
13 //! Free Software Foundation; either version 3 of the License, or
14 //! (at your option) any later version.
15 //!
16 //! This program is distributed in the hope that it will be useful, but
17 //! WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
18 //! or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
19 //! more details. You should have received a copy of the GNU General Public
20 //! License along with this program. If not, see [http://www.gnu.org/licenses/].
21
22 //! @section Synopsis
23 //!
24 //! Recursive-descent parenthesis checker.
25
26 #include "a68g.h"
27 #include "a68g-parser.h"
28
29 // After this checker, we know that at least brackets are matched.
30 // This stabilises later parser phases.
31 // Top-down parsing is done to place error diagnostics near offending lines.
32
33 //! @brief Intelligible diagnostics for the bracket checker.
34
35 void bracket_check_error (char *txt, int n, char *bra, char *ket)
36 {
37 if (n != 0) {
38 BUFFER b;
39 ASSERT (snprintf (b, SNPRINTF_SIZE, "\"%s\" without matching \"%s\"", (n > 0 ? bra : ket), (n > 0 ? ket : bra)) >= 0);
40 if (strlen (txt) > 0) {
41 bufcat (txt, " and ", BUFFER_SIZE);
42 }
43 bufcat (txt, b, BUFFER_SIZE);
44 }
45 }
46
47 //! @brief Diagnose brackets in local branch of the tree.
48
49 char *bracket_check_diagnose (NODE_T * p)
50 {
51 int begins = 0, opens = 0, format_delims = 0, format_opens = 0, subs = 0, ifs = 0, cases = 0, dos = 0, accos = 0;
52 for (; p != NO_NODE; FORWARD (p)) {
53 switch (ATTRIBUTE (p)) {
54 case BEGIN_SYMBOL:
55 {
56 begins++;
57 break;
58 }
59 case END_SYMBOL:
60 {
61 begins--;
62 break;
63 }
64 case OPEN_SYMBOL:
65 {
66 opens++;
67 break;
68 }
69 case CLOSE_SYMBOL:
70 {
71 opens--;
72 break;
73 }
74 case ACCO_SYMBOL:
75 {
76 accos++;
77 break;
78 }
79 case OCCA_SYMBOL:
80 {
81 accos--;
82 break;
83 }
84 case FORMAT_DELIMITER_SYMBOL:
85 {
86 if (format_delims == 0) {
87 format_delims = 1;
88 } else {
89 format_delims = 0;
90 }
91 break;
92 }
93 case FORMAT_OPEN_SYMBOL:
94 {
95 format_opens++;
96 break;
97 }
98 case FORMAT_CLOSE_SYMBOL:
99 {
100 format_opens--;
101 break;
102 }
103 case SUB_SYMBOL:
104 {
105 subs++;
106 break;
107 }
108 case BUS_SYMBOL:
109 {
110 subs--;
111 break;
112 }
113 case IF_SYMBOL:
114 {
115 ifs++;
116 break;
117 }
118 case FI_SYMBOL:
119 {
120 ifs--;
121 break;
122 }
123 case CASE_SYMBOL:
124 {
125 cases++;
126 break;
127 }
128 case ESAC_SYMBOL:
129 {
130 cases--;
131 break;
132 }
133 case DO_SYMBOL:
134 {
135 dos++;
136 break;
137 }
138 case OD_SYMBOL:
139 {
140 dos--;
141 break;
142 }
143 }
144 }
145 A68 (edit_line)[0] = NULL_CHAR;
146 bracket_check_error (A68 (edit_line), begins, "BEGIN", "END");
147 bracket_check_error (A68 (edit_line), opens, "(", ")");
148 bracket_check_error (A68 (edit_line), format_opens, "(", ")");
149 bracket_check_error (A68 (edit_line), format_delims, "$", "$");
150 bracket_check_error (A68 (edit_line), accos, "{", "}");
151 bracket_check_error (A68 (edit_line), subs, "[", "]");
152 bracket_check_error (A68 (edit_line), ifs, "IF", "FI");
153 bracket_check_error (A68 (edit_line), cases, "CASE", "ESAC");
154 bracket_check_error (A68 (edit_line), dos, "DO", "OD");
155 return A68 (edit_line);
156 }
157
158 //! @brief Driver for locally diagnosing non-matching tokens.
159
160 NODE_T *bracket_check_parse (NODE_T * top, NODE_T * p)
161 {
162 BOOL_T ignore_token;
163 for (; p != NO_NODE; FORWARD (p)) {
164 int ket = STOP;
165 NODE_T *q = NO_NODE;
166 ignore_token = A68_FALSE;
167 switch (ATTRIBUTE (p)) {
168 case BEGIN_SYMBOL:
169 {
170 ket = END_SYMBOL;
171 q = bracket_check_parse (top, NEXT (p));
172 break;
173 }
174 case OPEN_SYMBOL:
175 {
176 ket = CLOSE_SYMBOL;
177 q = bracket_check_parse (top, NEXT (p));
178 break;
179 }
180 case ACCO_SYMBOL:
181 {
182 ket = OCCA_SYMBOL;
183 q = bracket_check_parse (top, NEXT (p));
184 break;
185 }
186 case FORMAT_OPEN_SYMBOL:
187 {
188 ket = FORMAT_CLOSE_SYMBOL;
189 q = bracket_check_parse (top, NEXT (p));
190 break;
191 }
192 case SUB_SYMBOL:
193 {
194 ket = BUS_SYMBOL;
195 q = bracket_check_parse (top, NEXT (p));
196 break;
197 }
198 case IF_SYMBOL:
199 {
200 ket = FI_SYMBOL;
201 q = bracket_check_parse (top, NEXT (p));
202 break;
203 }
204 case CASE_SYMBOL:
205 {
206 ket = ESAC_SYMBOL;
207 q = bracket_check_parse (top, NEXT (p));
208 break;
209 }
210 case DO_SYMBOL:
211 {
212 ket = OD_SYMBOL;
213 q = bracket_check_parse (top, NEXT (p));
214 break;
215 }
216 case END_SYMBOL:
217 case OCCA_SYMBOL:
218 case CLOSE_SYMBOL:
219 case FORMAT_CLOSE_SYMBOL:
220 case BUS_SYMBOL:
221 case FI_SYMBOL:
222 case ESAC_SYMBOL:
223 case OD_SYMBOL:
224 {
225 return p;
226 }
227 default:
228 {
229 ignore_token = A68_TRUE;
230 }
231 }
232 if (ignore_token) {
233 ;
234 } else if (q != NO_NODE && IS (q, ket)) {
235 p = q;
236 } else if (q == NO_NODE) {
237 char *diag = bracket_check_diagnose (top);
238 diagnostic (A68_SYNTAX_ERROR, p, ERROR_PARENTHESIS, (strlen (diag) > 0 ? diag : INFO_MISSING_KEYWORDS));
239 longjmp (A68_PARSER (top_down_crash_exit), 1);
240 } else {
241 char *diag = bracket_check_diagnose (top);
242 diagnostic (A68_SYNTAX_ERROR, p, ERROR_PARENTHESIS_2, ATTRIBUTE (q), LINE (INFO (q)), ket, (strlen (diag) > 0 ? diag : INFO_MISSING_KEYWORDS));
243 longjmp (A68_PARSER (top_down_crash_exit), 1);
244 }
245 }
246 return NO_NODE;
247 }
248
249 //! @brief Driver for globally diagnosing non-matching tokens.
250
251 void check_parenthesis (NODE_T * top)
252 {
253 if (!setjmp (A68_PARSER (top_down_crash_exit))) {
254 if (bracket_check_parse (top, top) != NO_NODE) {
255 diagnostic (A68_SYNTAX_ERROR, top, ERROR_PARENTHESIS, INFO_MISSING_KEYWORDS);
256 }
257 }
258 }