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-2024 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 buf;
39 BUFCLR (buf);
40 ASSERT (a68_bufprt (buf, SNPRINTF_SIZE, "\"%s\" without matching \"%s\"", (n > 0 ? bra : ket), (n > 0 ? ket : bra)) >= 0);
41 if (strlen (txt) > 0) {
42 a68_bufcat (txt, " or ", BUFFER_SIZE);
43 }
44 a68_bufcat (txt, buf, BUFFER_SIZE);
45 }
46 }
47
48 //! @brief Diagnose brackets in local branch of the tree.
49
50 char *bracket_check_diagnose (NODE_T * p)
51 {
52 int begins = 0, opens = 0, format_delims = 0, format_opens = 0, subs = 0, ifs = 0, cases = 0, dos = 0, accos = 0;
53 for (; p != NO_NODE; FORWARD (p)) {
54 switch (ATTRIBUTE (p)) {
55 case BEGIN_SYMBOL: {
56 begins++;
57 break;
58 }
59 case END_SYMBOL: {
60 begins--;
61 break;
62 }
63 case OPEN_SYMBOL: {
64 opens++;
65 break;
66 }
67 case CLOSE_SYMBOL: {
68 opens--;
69 break;
70 }
71 case ACCO_SYMBOL: {
72 accos++;
73 break;
74 }
75 case OCCA_SYMBOL: {
76 accos--;
77 break;
78 }
79 case FORMAT_DELIMITER_SYMBOL: {
80 if (format_delims == 0) {
81 format_delims = 1;
82 } else {
83 format_delims = 0;
84 }
85 break;
86 }
87 case FORMAT_OPEN_SYMBOL: {
88 format_opens++;
89 break;
90 }
91 case FORMAT_CLOSE_SYMBOL: {
92 format_opens--;
93 break;
94 }
95 case SUB_SYMBOL: {
96 subs++;
97 break;
98 }
99 case BUS_SYMBOL: {
100 subs--;
101 break;
102 }
103 case IF_SYMBOL: {
104 ifs++;
105 break;
106 }
107 case FI_SYMBOL: {
108 ifs--;
109 break;
110 }
111 case CASE_SYMBOL: {
112 cases++;
113 break;
114 }
115 case ESAC_SYMBOL: {
116 cases--;
117 break;
118 }
119 case DO_SYMBOL: {
120 dos++;
121 break;
122 }
123 case OD_SYMBOL: {
124 dos--;
125 break;
126 }
127 }
128 }
129 A68 (edit_line)[0] = NULL_CHAR;
130 bracket_check_error (A68 (edit_line), begins, "BEGIN", "END");
131 bracket_check_error (A68 (edit_line), opens, "(", ")");
132 bracket_check_error (A68 (edit_line), format_opens, "(", ")");
133 bracket_check_error (A68 (edit_line), format_delims, "$", "$");
134 bracket_check_error (A68 (edit_line), accos, "{", "}");
135 bracket_check_error (A68 (edit_line), subs, "[", "]");
136 bracket_check_error (A68 (edit_line), ifs, "IF", "FI");
137 bracket_check_error (A68 (edit_line), cases, "CASE", "ESAC");
138 bracket_check_error (A68 (edit_line), dos, "DO", "OD");
139 return A68 (edit_line);
140 }
141
142 //! @brief Driver for locally diagnosing non-matching tokens.
143
144 NODE_T *bracket_check_parse (NODE_T * top, NODE_T * p)
145 {
146 for (; p != NO_NODE; FORWARD (p)) {
147 int ket = STOP;
148 NODE_T *q = NO_NODE;
149 BOOL_T ignore_token = A68_FALSE;
150 switch (ATTRIBUTE (p)) {
151 case BEGIN_SYMBOL: {
152 ket = END_SYMBOL;
153 q = bracket_check_parse (top, NEXT (p));
154 break;
155 }
156 case OPEN_SYMBOL: {
157 ket = CLOSE_SYMBOL;
158 q = bracket_check_parse (top, NEXT (p));
159 break;
160 }
161 case ACCO_SYMBOL: {
162 ket = OCCA_SYMBOL;
163 q = bracket_check_parse (top, NEXT (p));
164 break;
165 }
166 case FORMAT_OPEN_SYMBOL: {
167 ket = FORMAT_CLOSE_SYMBOL;
168 q = bracket_check_parse (top, NEXT (p));
169 break;
170 }
171 case SUB_SYMBOL: {
172 ket = BUS_SYMBOL;
173 q = bracket_check_parse (top, NEXT (p));
174 break;
175 }
176 case IF_SYMBOL: {
177 ket = FI_SYMBOL;
178 q = bracket_check_parse (top, NEXT (p));
179 break;
180 }
181 case CASE_SYMBOL: {
182 ket = ESAC_SYMBOL;
183 q = bracket_check_parse (top, NEXT (p));
184 break;
185 }
186 case DO_SYMBOL: {
187 ket = OD_SYMBOL;
188 q = bracket_check_parse (top, NEXT (p));
189 break;
190 }
191 case END_SYMBOL:
192 case OCCA_SYMBOL:
193 case CLOSE_SYMBOL:
194 case FORMAT_CLOSE_SYMBOL:
195 case BUS_SYMBOL:
196 case FI_SYMBOL:
197 case ESAC_SYMBOL:
198 case OD_SYMBOL: {
199 return p;
200 }
201 default: {
202 ignore_token = A68_TRUE;
203 }
204 }
205 if (ignore_token) {
206 ;
207 } else if (q != NO_NODE && IS (q, ket)) {
208 p = q;
209 } else if (q == NO_NODE) {
210 char *diag = bracket_check_diagnose (top);
211 diagnostic (A68_SYNTAX_ERROR, p, ERROR_PARENTHESIS, (strlen (diag) > 0 ? diag : INFO_MISSING_KEYWORDS));
212 longjmp (A68_PARSER (top_down_crash_exit), 1);
213 } else {
214 char *diag = bracket_check_diagnose (top);
215 diagnostic (A68_SYNTAX_ERROR, p, ERROR_PARENTHESIS_2, ATTRIBUTE (q), LINE (INFO (q)), ket, (strlen (diag) > 0 ? diag : INFO_MISSING_KEYWORDS));
216 longjmp (A68_PARSER (top_down_crash_exit), 1);
217 }
218 }
219 return NO_NODE;
220 }
221
222 //! @brief Driver for globally diagnosing non-matching tokens.
223
224 void check_parenthesis (NODE_T * top)
225 {
226 if (!setjmp (A68_PARSER (top_down_crash_exit))) {
227 if (bracket_check_parse (top, top) != NO_NODE) {
228 diagnostic (A68_SYNTAX_ERROR, top, ERROR_PARENTHESIS, INFO_MISSING_KEYWORDS);
229 }
230 }
231 }
© 2002-2024 J.M. van der Veer (jmvdveer@xs4all.nl)
|