1------------------------------------------------------------------------------ 2-- -- 3-- GNAT COMPILER COMPONENTS -- 4-- -- 5-- P A R . S Y N C -- 6-- -- 7-- B o d y -- 8-- -- 9-- Copyright (C) 1992-2020, Free Software Foundation, Inc. -- 10-- -- 11-- GNAT is free software; you can redistribute it and/or modify it under -- 12-- terms of the GNU General Public License as published by the Free Soft- -- 13-- ware Foundation; either version 3, or (at your option) any later ver- -- 14-- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- 15-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- 16-- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -- 17-- for more details. You should have received a copy of the GNU General -- 18-- Public License distributed with GNAT; see file COPYING3. If not, go to -- 19-- http://www.gnu.org/licenses for a complete copy of the license. -- 20-- -- 21-- GNAT was originally developed by the GNAT team at New York University. -- 22-- Extensive contributions were provided by Ada Core Technologies Inc. -- 23-- -- 24------------------------------------------------------------------------------ 25 26separate (Par) 27package body Sync is 28 29 procedure Resync_Init; 30 -- This routine is called on initiating a resynchronization action 31 32 procedure Resync_Resume; 33 -- This routine is called on completing a resynchronization action 34 35 ------------------- 36 -- Resync_Choice -- 37 ------------------- 38 39 procedure Resync_Choice is 40 begin 41 Resync_Init; 42 43 -- Loop till we get a token that terminates a choice. Note that EOF is 44 -- one such token, so we are sure to get out of this loop eventually. 45 46 while Token not in Token_Class_Cterm loop 47 Scan; 48 end loop; 49 50 Resync_Resume; 51 end Resync_Choice; 52 53 ------------------ 54 -- Resync_Cunit -- 55 ------------------ 56 57 procedure Resync_Cunit is 58 begin 59 Resync_Init; 60 61 while Token not in Token_Class_Cunit 62 and then Token /= Tok_EOF 63 loop 64 Scan; 65 end loop; 66 67 Resync_Resume; 68 end Resync_Cunit; 69 70 ----------------------- 71 -- Resync_Expression -- 72 ----------------------- 73 74 procedure Resync_Expression is 75 Paren_Count : Int; 76 77 begin 78 Resync_Init; 79 Paren_Count := 0; 80 81 loop 82 -- Terminating tokens are those in class Eterm and also RANGE, 83 -- DIGITS or DELTA if not preceded by an apostrophe (if they are 84 -- preceded by an apostrophe, then they are attributes). In addition, 85 -- at the outer parentheses level only, we also consider a comma, 86 -- right parenthesis or vertical bar to terminate an expression. 87 88 if Token in Token_Class_Eterm 89 90 or else (Token in Token_Class_Atkwd 91 and then Prev_Token /= Tok_Apostrophe) 92 93 or else (Paren_Count = 0 94 and then 95 (Token = Tok_Comma 96 or else Token = Tok_Right_Paren 97 or else Token = Tok_Vertical_Bar)) 98 then 99 -- A special check: if we stop on the ELSE of OR ELSE or the 100 -- THEN of AND THEN, keep going, because this is not really an 101 -- expression terminator after all. Also, keep going past WITH 102 -- since this can be part of an extension aggregate 103 104 if (Token = Tok_Else and then Prev_Token = Tok_Or) 105 or else (Token = Tok_Then and then Prev_Token = Tok_And) 106 or else Token = Tok_With 107 then 108 null; 109 else 110 exit; 111 end if; 112 end if; 113 114 if Token = Tok_Left_Paren then 115 Paren_Count := Paren_Count + 1; 116 117 elsif Token = Tok_Right_Paren then 118 Paren_Count := Paren_Count - 1; 119 120 end if; 121 122 Scan; -- past token to be skipped 123 end loop; 124 125 Resync_Resume; 126 end Resync_Expression; 127 128 ----------------- 129 -- Resync_Init -- 130 ----------------- 131 132 procedure Resync_Init is 133 begin 134 -- The following check makes sure we do not get stuck in an infinite 135 -- loop resynchronizing and getting nowhere. If we are called to do a 136 -- resynchronize and we are exactly at the same point that we left off 137 -- on the last resynchronize call, then we force at least one token to 138 -- be skipped so that we make progress. 139 140 if Token_Ptr = Last_Resync_Point then 141 Scan; -- to skip at least one token 142 end if; 143 144 -- Output extra error message if debug R flag is set 145 146 if Debug_Flag_R then 147 Error_Msg_SC ("resynchronizing!"); 148 end if; 149 end Resync_Init; 150 151 ---------------------------------- 152 -- Resync_Past_Malformed_Aspect -- 153 ---------------------------------- 154 155 procedure Resync_Past_Malformed_Aspect is 156 begin 157 Resync_Init; 158 159 loop 160 -- A comma may separate two aspect specifications, but it may also 161 -- delimit multiple arguments of a single aspect. 162 163 if Token = Tok_Comma then 164 declare 165 Scan_State : Saved_Scan_State; 166 167 begin 168 Save_Scan_State (Scan_State); 169 Scan; -- past comma 170 171 -- The identifier following the comma is a valid aspect, the 172 -- current malformed aspect has been successfully skipped. 173 174 if Token = Tok_Identifier 175 and then Get_Aspect_Id (Token_Name) /= No_Aspect 176 then 177 Restore_Scan_State (Scan_State); 178 exit; 179 180 -- The comma is delimiting multiple arguments of an aspect 181 182 else 183 Restore_Scan_State (Scan_State); 184 end if; 185 end; 186 187 -- An IS signals the last aspect specification when the related 188 -- context is a body. 189 190 elsif Token = Tok_Is then 191 exit; 192 193 -- A semicolon signals the last aspect specification 194 195 elsif Token = Tok_Semicolon then 196 exit; 197 198 -- In the case of a mistyped semicolon, any token which follows a 199 -- semicolon signals the last aspect specification. 200 201 elsif Token in Token_Class_After_SM then 202 exit; 203 end if; 204 205 -- Keep on resyncing 206 207 Scan; 208 end loop; 209 210 -- Fall out of loop with resynchronization complete 211 212 Resync_Resume; 213 end Resync_Past_Malformed_Aspect; 214 215 --------------------------- 216 -- Resync_Past_Semicolon -- 217 --------------------------- 218 219 procedure Resync_Past_Semicolon is 220 begin 221 Resync_Init; 222 223 loop 224 -- Done if we are at a semicolon 225 226 if Token = Tok_Semicolon then 227 Scan; -- past semicolon 228 exit; 229 230 -- Done if we are at a token which normally appears only after 231 -- a semicolon. One special glitch is that the keyword private is 232 -- in this category only if it does NOT appear after WITH. 233 234 elsif Token in Token_Class_After_SM 235 and then (Token /= Tok_Private or else Prev_Token /= Tok_With) 236 then 237 exit; 238 239 -- Otherwise keep going 240 241 else 242 Scan; 243 end if; 244 end loop; 245 246 -- Fall out of loop with resynchronization complete 247 248 Resync_Resume; 249 end Resync_Past_Semicolon; 250 251 ---------------------------------------------- 252 -- Resync_Past_Semicolon_Or_To_Loop_Or_Then -- 253 ---------------------------------------------- 254 255 procedure Resync_Past_Semicolon_Or_To_Loop_Or_Then is 256 begin 257 Resync_Init; 258 259 loop 260 -- Done if at semicolon 261 262 if Token = Tok_Semicolon then 263 Scan; -- past the semicolon 264 exit; 265 266 -- Done if we are at a token which normally appears only after 267 -- a semicolon. One special glitch is that the keyword private is 268 -- in this category only if it does NOT appear after WITH. 269 270 elsif Token in Token_Class_After_SM 271 and then (Token /= Tok_Private or else Prev_Token /= Tok_With) 272 then 273 exit; 274 275 -- Done if we are at THEN or LOOP 276 277 elsif Token = Tok_Then or else Token = Tok_Loop then 278 exit; 279 280 -- Otherwise keep going 281 282 else 283 Scan; 284 end if; 285 end loop; 286 287 -- Fall out of loop with resynchronization complete 288 289 Resync_Resume; 290 end Resync_Past_Semicolon_Or_To_Loop_Or_Then; 291 292 ------------------- 293 -- Resync_Resume -- 294 ------------------- 295 296 procedure Resync_Resume is 297 begin 298 -- Save resync point (see special test in Resync_Init) 299 300 Last_Resync_Point := Token_Ptr; 301 302 if Debug_Flag_R then 303 Error_Msg_SC ("resuming here!"); 304 end if; 305 end Resync_Resume; 306 307 --------------------------- 308 -- Resync_Semicolon_List -- 309 --------------------------- 310 311 procedure Resync_Semicolon_List is 312 Paren_Count : Int; 313 314 begin 315 Resync_Init; 316 Paren_Count := 0; 317 318 loop 319 if Token = Tok_EOF 320 or else Token = Tok_Semicolon 321 or else Token = Tok_Is 322 or else Token in Token_Class_After_SM 323 then 324 exit; 325 326 elsif Token = Tok_Left_Paren then 327 Paren_Count := Paren_Count + 1; 328 329 elsif Token = Tok_Right_Paren then 330 if Paren_Count = 0 then 331 exit; 332 else 333 Paren_Count := Paren_Count - 1; 334 end if; 335 end if; 336 337 Scan; 338 end loop; 339 340 Resync_Resume; 341 end Resync_Semicolon_List; 342 343 ------------------------- 344 -- Resync_To_Semicolon -- 345 ------------------------- 346 347 procedure Resync_To_Semicolon is 348 begin 349 Resync_Init; 350 351 loop 352 -- Done if we are at a semicolon 353 354 if Token = Tok_Semicolon then 355 exit; 356 357 -- Done if we are at a token which normally appears only after 358 -- a semicolon. One special glitch is that the keyword private is 359 -- in this category only if it does NOT appear after WITH. 360 361 elsif Token in Token_Class_After_SM 362 and then (Token /= Tok_Private or else Prev_Token /= Tok_With) 363 then 364 exit; 365 366 -- Otherwise keep going 367 368 else 369 Scan; 370 end if; 371 end loop; 372 373 -- Fall out of loop with resynchronization complete 374 375 Resync_Resume; 376 end Resync_To_Semicolon; 377 378 -------------------- 379 -- Resync_To_When -- 380 -------------------- 381 382 procedure Resync_To_When is 383 begin 384 Resync_Init; 385 386 loop 387 -- Done if at semicolon, WHEN or IS 388 389 if Token = Tok_Semicolon 390 or else Token = Tok_When 391 or else Token = Tok_Is 392 then 393 exit; 394 395 -- Otherwise keep going 396 397 else 398 Scan; 399 end if; 400 end loop; 401 402 -- Fall out of loop with resynchronization complete 403 404 Resync_Resume; 405 end Resync_To_When; 406 407end Sync; 408