| File: | src/linear.c |
| Warning: | line 776, column 38 Value stored to 'mate' during its initialization is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /***************************************************************************** |
| 2 | * |
| 3 | * linear.c: Bracketing of piles. |
| 4 | * |
| 5 | * Copyright (c) 1990-2007 Aldor Software Organization Ltd (Aldor.org). |
| 6 | * |
| 7 | ****************************************************************************/ |
| 8 | |
| 9 | /* |
| 10 | * Convert newline and indentation information into bracketing. |
| 11 | * The NewLine tokens are removed and SetTab, BackSet and BackTabs are added. |
| 12 | * |
| 13 | * The original list of tokens is modified. |
| 14 | * |
| 15 | * Note that most of the function header comments in this file were added |
| 16 | * post-facto and may be incorrect. |
| 17 | */ |
| 18 | |
| 19 | #include "debug.h" |
| 20 | #include "format.h" |
| 21 | #include "linear.h" |
| 22 | #include "store.h" |
| 23 | #include "fint.h" |
| 24 | #include "comsg.h" |
| 25 | #include "util.h" |
| 26 | |
| 27 | Bool linDebug = false((int) 0); |
| 28 | #define linDEBUGif (!linDebug) { } else afprintf DEBUG_IF(lin)if (!linDebug) { } else afprintf |
| 29 | |
| 30 | /**************************************************************************** |
| 31 | * |
| 32 | * :: Forward decls |
| 33 | * |
| 34 | ****************************************************************************/ |
| 35 | |
| 36 | localstatic Token linKeyword (Token, TokenTag); |
| 37 | |
| 38 | localstatic int linIndentation (TokenList); |
| 39 | localstatic TokenList linUseNeededSep (TokenList); |
| 40 | localstatic TokenList linXTokens (TokenList, TokenTag); |
| 41 | localstatic TokenList linXBlankLines (TokenList); |
| 42 | localstatic TokenList linCheckBalance (TokenList); |
| 43 | localstatic TokenList linISepAfterDontPiles (TokenList); |
| 44 | localstatic TokenList linXSep (TokenList); |
| 45 | |
| 46 | # define linXComments(tl)linXTokens((tl), TK_Comment) linXTokens((tl), TK_Comment) |
| 47 | # define linXNewLines(tl)linXTokens((tl), KW_NewLine) linXTokens((tl), KW_NewLine) |
| 48 | # define tokIsNonStarter(t)(((tokInfoTable[((t)->tag)-TK_START]).isFollower) || ((tokInfoTable [((t)->tag)-TK_START]).isCloser)) (tokIsFollower(t)((tokInfoTable[((t)->tag)-TK_START]).isFollower) || tokIsCloser(t)((tokInfoTable[((t)->tag)-TK_START]).isCloser)) |
| 49 | |
| 50 | # define MootIndentation(-1) (-1) |
| 51 | |
| 52 | # define DoPileStartKW_StartPile KW_StartPile /* #pile */ |
| 53 | # define DoPileEndKW_EndPile KW_EndPile /* #endpile */ |
| 54 | |
| 55 | # define DontPileStartKW_OCurly KW_OCurly /* { */ |
| 56 | # define DontPileSepKW_Semicolon KW_Semicolon /* ; */ |
| 57 | # define DontPileEndKW_CCurly KW_CCurly /* } */ |
| 58 | |
| 59 | |
| 60 | /**************************************************************************** |
| 61 | * |
| 62 | * :: LNodeTree data structure. |
| 63 | * |
| 64 | ****************************************************************************/ |
| 65 | |
| 66 | /* |
| 67 | * The LNodeTree structure represents in tree form the information |
| 68 | * about whether to pile and, if so, line boundaries. |
| 69 | * |
| 70 | * The input |
| 71 | * |
| 72 | * {| |
| 73 | * a |
| 74 | * b |
| 75 | * c |
| 76 | * d { e |
| 77 | * h } i |
| 78 | * l { |
| 79 | * n |
| 80 | * o {| p |
| 81 | * q |
| 82 | * r |} |
| 83 | * t |
| 84 | * u } |
| 85 | * v |
| 86 | * w z |
| 87 | * |} |
| 88 | * |
| 89 | * becomes |
| 90 | * |
| 91 | * {| <a> <b> <c> <d { e h } i> <l { n o {| <p> <q> <r> |} t u }> <v> <w z> |} |
| 92 | * |
| 93 | * Note that since piling brackets {| and |} have been replaced by #pile |
| 94 | * and #endpile, the example above is overly complicated and could not be |
| 95 | * represented in Aldor. Also note that this structure assumes that most |
| 96 | * programs will be piled whereas now they are normally non-piled. The |
| 97 | * two forms do not normally appear together in the same source file. |
| 98 | */ |
| 99 | |
| 100 | |
| 101 | /* Note that LN_1Tok and LN_NTok could be merged */ |
| 102 | enum lnodeKind { |
| 103 | LN_1Tok, /* a */ |
| 104 | LN_NTok, /* <w z> -- Has any NewLine token. */ |
| 105 | LN_NNodes, /* <d { e h } i> -- Has any NewLine token. */ |
| 106 | LN_DoPile /* {| <p> <q> <r> |} -- Has {| |} tokens. */ |
| 107 | }; |
| 108 | |
| 109 | typedef Enum(lnodeKind)enum lnodeKind LNodeKind; |
| 110 | typedef struct lnode *LNodeTree; |
| 111 | |
| 112 | union lnodeArg { |
| 113 | Token tok; |
| 114 | LNodeTree lnode; |
| 115 | }; |
| 116 | |
| 117 | struct lnode { |
| 118 | LNodeKind kind; |
| 119 | ULong has; |
| 120 | Length indent; |
| 121 | Length argc; |
| 122 | union lnodeArg argv[NARY10]; |
| 123 | }; |
| 124 | |
| 125 | #define HAS_NonCom(1<<0) (1<<0) |
| 126 | #define HAS_NonBlank(1<<1) (1<<1) |
| 127 | |
| 128 | #define linIsBlank(lnt)(!((lnt)->has & (1<<1))) (!((lnt)->has & HAS_NonBlank(1<<1))) |
| 129 | #define linIsCom(lnt)(!((lnt)->has & (1<<0))) (!((lnt)->has & HAS_NonCom(1<<0))) |
| 130 | |
| 131 | |
| 132 | DECLARE_LIST(LNodeTree)typedef struct LNodeTreeListCons { LNodeTree first; struct LNodeTreeListCons *rest; } *LNodeTreeList; struct LNodeTree_listOpsStruct { LNodeTreeList (*Cons) (LNodeTree, LNodeTreeList); LNodeTreeList (*Singleton ) (LNodeTree); LNodeTreeList (*List) (int n, ...); LNodeTreeList (*Listv) (va_list argp); LNodeTreeList (*ListNull) (LNodeTree , ...); Bool (*Equal) (LNodeTreeList, LNodeTreeList, Bool (*f ) (LNodeTree, LNodeTree)); LNodeTree (*Find) (LNodeTreeList, LNodeTree , Bool(*eq)(LNodeTree,LNodeTree) , int *); LNodeTree (*Match) (LNodeTreeList, void *, Bool(*match)(LNodeTree, void *), int *); LNodeTreeList (*MatchAll) (LNodeTreeList, void *, Bool(* match)(LNodeTree, void *)); LNodeTreeList (*FreeCons) (LNodeTreeList ); void (*Free) (LNodeTreeList); LNodeTreeList (*FreeTo) (LNodeTreeList , LNodeTreeList); void (*FreeDeeply) (LNodeTreeList, void (*f )(LNodeTree)); LNodeTreeList (*FreeDeeplyTo) (LNodeTreeList, LNodeTreeList , void (*f) (LNodeTree) ); LNodeTreeList (*FreeIfSat) (LNodeTreeList , void (*f)(LNodeTree), Bool (*s)(LNodeTree)); LNodeTree (*Elt ) (LNodeTreeList, Length); LNodeTreeList (*Drop) (LNodeTreeList , Length); LNodeTreeList (*LastCons) (LNodeTreeList); Length ( *_Length) (LNodeTreeList); Bool (*IsLength) (LNodeTreeList, Length ); Bool (*IsShorter) (LNodeTreeList, Length); Bool (*IsLonger ) (LNodeTreeList, Length); LNodeTreeList (*Copy) (LNodeTreeList ); LNodeTreeList (*CopyTo) (LNodeTreeList, LNodeTreeList); LNodeTreeList (*CopyDeeply) (LNodeTreeList, LNodeTree (*)(LNodeTree)); LNodeTreeList (*CopyDeeplyTo) (LNodeTreeList, LNodeTreeList, LNodeTree (*) (LNodeTree)); LNodeTreeList (*Map) (LNodeTree (*f)(LNodeTree) , LNodeTreeList); LNodeTreeList (*NMap) (LNodeTree (*f)(LNodeTree ), LNodeTreeList); LNodeTreeList (*Reverse) (LNodeTreeList); LNodeTreeList (*NReverse) (LNodeTreeList); LNodeTreeList (*Concat) (LNodeTreeList , LNodeTreeList); LNodeTreeList (*NConcat) (LNodeTreeList, LNodeTreeList ); Bool (*Memq) (LNodeTreeList, LNodeTree); Bool (*Member) (LNodeTreeList , LNodeTree, Bool(*eq)(LNodeTree,LNodeTree) ); Bool (*ContainsAllq ) (LNodeTreeList, LNodeTreeList); Bool (*ContainsAnyq) (LNodeTreeList , LNodeTreeList); Bool (*ContainsAll) (LNodeTreeList, LNodeTreeList , Bool (*eq)(LNodeTree, LNodeTree)); Bool (*ContainsAny) (LNodeTreeList , LNodeTreeList, Bool (*eq)(LNodeTree, LNodeTree)); int (*Posq ) (LNodeTreeList, LNodeTree); int (*Position) (LNodeTreeList, LNodeTree, Bool(*eq)(LNodeTree,LNodeTree) ); LNodeTreeList ( *NRemove) (LNodeTreeList, LNodeTree, Bool(*eq)(LNodeTree,LNodeTree ) ); void (*FillVector) (LNodeTree *, LNodeTreeList); int (*Print ) (FILE *, LNodeTreeList, int (*pr)(FILE *, LNodeTree) ); int (*GPrint) (FILE *, LNodeTreeList, int (*pr)(FILE *, LNodeTree ), char *l,char *m,char *r); int (*Format) (OStream, CString, LNodeTreeList); }; extern struct LNodeTree_listOpsStruct const *LNodeTree_listPointer; |
| 133 | CREATE_LIST (LNodeTree)struct LNodeTree_listOpsStruct const *LNodeTree_listPointer = (struct LNodeTree_listOpsStruct const *) &ptrlistOps; |
| 134 | |
| 135 | localstatic LNodeTree lntNewEmpty (LNodeKind, Length); |
| 136 | localstatic void lntFree (LNodeTree); |
| 137 | localstatic void lntFreeNode (LNodeTree); |
| 138 | |
| 139 | localstatic ULong lntTokHas (TokenTag); |
| 140 | localstatic Token lntFirstTok (LNodeTree); |
| 141 | localstatic Token lntLastTok (LNodeTree); |
| 142 | localstatic Token lntLastTokLessNL(LNodeTree); |
| 143 | |
| 144 | localstatic LNodeTree lntTok (Token); |
| 145 | localstatic LNodeTree lntConcat (LNodeTree, LNodeTree); |
| 146 | localstatic LNodeTree lntSeparate (LNodeTree, TokenTag, LNodeTree); |
| 147 | localstatic LNodeTree lntWrap (TokenTag, LNodeTree, TokenTag); |
| 148 | |
| 149 | localstatic TokenList lntToTokenList (LNodeTree); |
| 150 | localstatic TokenList lntToTokenList0 (LNodeTree, TokenList); |
| 151 | localstatic TokenList lntConsNL (TokenList); |
| 152 | localstatic LNodeTree lntFrTokenList (TokenList); |
| 153 | |
| 154 | localstatic LNodeTree lin2DRules (LNodeTree); |
| 155 | |
| 156 | |
| 157 | |
| 158 | localstatic LNodeTree |
| 159 | lntNewEmpty(LNodeKind kind, Length argc) |
| 160 | { |
| 161 | LNodeTree lnt; |
| 162 | |
| 163 | lnt = (LNodeTree) stoAlloc(OB_Other0, |
| 164 | fullsizeof(struct lnode,(sizeof(struct lnode) + (argc) * sizeof(union lnodeArg) - 10 * sizeof(union lnodeArg)) |
| 165 | argc, union lnodeArg)(sizeof(struct lnode) + (argc) * sizeof(union lnodeArg) - 10 * sizeof(union lnodeArg))); |
| 166 | lnt->kind = kind; |
| 167 | lnt->has = 0; |
| 168 | lnt->indent = -1; |
| 169 | lnt->argc = argc; |
| 170 | return lnt; |
| 171 | } |
| 172 | |
| 173 | localstatic void |
| 174 | lntFree(LNodeTree lnt) |
| 175 | { |
| 176 | if (!lnt) return; |
| 177 | |
| 178 | if (lnt->kind != LN_1Tok && lnt->kind != LN_NTok) { |
| 179 | int i; |
| 180 | for (i = 0; i < lnt->argc; i++) lntFree(lnt->argv[i].lnode); |
| 181 | } |
| 182 | lntFreeNode(lnt); |
| 183 | } |
| 184 | |
| 185 | localstatic void |
| 186 | lntFreeNode(LNodeTree lnt) |
| 187 | { |
| 188 | stoFree((Pointer) lnt); |
| 189 | } |
| 190 | |
| 191 | |
| 192 | localstatic int |
| 193 | lntPrint(FILE *fout, LNodeTree lnt) |
| 194 | { |
| 195 | int cc, i, n; |
| 196 | static int d = 0; |
| 197 | |
| 198 | if (!lnt) return fprintf(fout, "|0|"); |
| 199 | |
| 200 | n = lnt->argc; |
| 201 | cc = 0; |
| 202 | |
| 203 | d++; |
| 204 | switch (lnt->kind) { |
| 205 | case LN_1Tok: |
| 206 | cc = fprintf(fout, "(: "); |
| 207 | cc += tokPrint(fout, lnt->argv[0].tok); |
| 208 | cc += fprintf(fout, " :)"); |
| 209 | break; |
| 210 | case LN_NTok: |
| 211 | cc = fprintf(fout, "<: "); |
| 212 | for (i = 0; i < n; i++) { |
| 213 | cc += fprintf(fout, " "); |
| 214 | cc += tokPrint(fout, lnt->argv[i].tok); |
| 215 | } |
| 216 | cc += fprintf(fout, " :>"); |
| 217 | break; |
| 218 | case LN_NNodes: |
| 219 | cc = fprintf(fout, "< %d: ", d); |
| 220 | for (i = 0; i < n; i++) |
| 221 | cc += lntPrint(fout, lnt->argv[i].lnode); |
| 222 | cc += fprintf(fout, " :%d >", d); |
| 223 | break; |
| 224 | case LN_DoPile: |
| 225 | cc = fprintf(fout, "{ %d: ", d); |
| 226 | for (i = 0; i < n; i++) |
| 227 | cc += lntPrint(fout, lnt->argv[i].lnode); |
| 228 | cc += fprintf(fout, " :%d }", d); |
| 229 | break; |
| 230 | } |
| 231 | d--; |
| 232 | cc += fprintf(fout, "%lx", lnt->has); |
| 233 | |
| 234 | return cc; |
| 235 | } |
| 236 | |
| 237 | /***************************************************************************** |
| 238 | * |
| 239 | * :: LNodeTree utilities |
| 240 | * |
| 241 | ****************************************************************************/ |
| 242 | |
| 243 | localstatic LNodeTree |
| 244 | lntTok(Token tok) |
| 245 | { |
| 246 | LNodeTree lnt = lntNewEmpty(LN_1Tok, 1); |
| 247 | lnt->argv[0].tok= tok; |
| 248 | lnt->has = lntTokHas(tokTag(tok)((TokenTag) (tok)->tag)); |
| 249 | lnt->indent = sposChar(tok->pos); |
| 250 | return lnt; |
| 251 | } |
| 252 | |
| 253 | localstatic LNodeTree |
| 254 | lntConcat(LNodeTree lnt, LNodeTree rnt) |
| 255 | { |
| 256 | LNodeTree tnt; |
| 257 | |
| 258 | if (! lnt) |
| 259 | tnt = rnt; |
| 260 | else if (! rnt) |
| 261 | tnt = lnt; |
| 262 | else { |
| 263 | tnt = lntNewEmpty(LN_NNodes, 2); |
| 264 | tnt->indent = lnt->indent; |
| 265 | tnt->has = lnt->has | rnt->has; |
| 266 | tnt->argv[0].lnode = lnt; |
| 267 | tnt->argv[1].lnode = rnt; |
| 268 | } |
| 269 | return tnt; |
| 270 | } |
| 271 | |
| 272 | localstatic LNodeTree |
| 273 | lntSeparate(LNodeTree lnt, TokenTag sep, LNodeTree rnt) |
| 274 | { |
| 275 | LNodeTree tnt; |
| 276 | Token tok = lntLastTok(lnt); |
| 277 | |
| 278 | tnt = lntNewEmpty(LN_NNodes, 3); |
| 279 | tnt->indent = lnt->indent; |
| 280 | tnt->has = lnt->has | lntTokHas(sep) | rnt->has; |
| 281 | tnt->argv[0].lnode = lnt; |
| 282 | tnt->argv[1].lnode = lntTok(linKeyword(tok, sep)); |
| 283 | tnt->argv[2].lnode = rnt; |
| 284 | |
| 285 | return tnt; |
| 286 | } |
| 287 | |
| 288 | localstatic LNodeTree |
| 289 | lntWrap(TokenTag open, LNodeTree lnt, TokenTag close) |
| 290 | { |
| 291 | LNodeTree tnt; |
| 292 | |
| 293 | Token otok = lntFirstTok(lnt); |
| 294 | Token ctok = lntLastTok(lnt); |
| 295 | |
| 296 | tnt = lntNewEmpty(LN_NNodes, 3); |
| 297 | tnt->indent = lnt->indent; |
| 298 | tnt->has = lntTokHas(open) | lnt->has | lntTokHas(close); |
| 299 | tnt->argv[0].lnode = lntTok(linKeyword(otok, open)); |
| 300 | tnt->argv[1].lnode = lnt; |
| 301 | tnt->argv[2].lnode = lntTok(linKeyword(ctok, close)); |
| 302 | |
| 303 | return tnt; |
| 304 | } |
| 305 | |
| 306 | localstatic ULong |
| 307 | lntTokHas(TokenTag tt) |
| 308 | { |
| 309 | switch (tt) { |
| 310 | case KW_NewLine: case TK_Comment: return 0; |
| 311 | case TK_PostDoc: case TK_PreDoc: return HAS_NonBlank(1<<1); |
| 312 | default: return HAS_NonBlank(1<<1) | HAS_NonCom(1<<0); |
| 313 | } |
| 314 | } |
| 315 | |
| 316 | localstatic Token |
| 317 | lntFirstTok(LNodeTree lnt) |
| 318 | { |
| 319 | if (!lnt) return 0; |
| 320 | |
| 321 | for (;;) { |
| 322 | if (lnt->argc == 0) return 0; |
| 323 | |
| 324 | switch (lnt->kind) { |
| 325 | case LN_1Tok: |
| 326 | case LN_NTok: |
| 327 | return lnt->argv[0].tok; |
| 328 | case LN_NNodes: |
| 329 | case LN_DoPile: |
| 330 | lnt = lnt->argv[0].lnode; |
| 331 | } |
| 332 | } |
| 333 | } |
| 334 | |
| 335 | localstatic Token |
| 336 | lntLastTok(LNodeTree lnt) |
| 337 | { |
| 338 | if (!lnt) return 0; |
| 339 | |
| 340 | for (;;) { |
| 341 | int n = lnt->argc; |
| 342 | |
| 343 | if (n == 0) return 0; |
| 344 | |
| 345 | switch (lnt->kind) { |
| 346 | case LN_1Tok: |
| 347 | return lnt->argv[0].tok; |
| 348 | case LN_NTok: |
| 349 | return lnt->argv[n-1].tok; |
| 350 | case LN_NNodes: |
| 351 | case LN_DoPile: |
| 352 | lnt = lnt->argv[n-1].lnode; |
| 353 | } |
| 354 | } |
| 355 | } |
| 356 | |
| 357 | localstatic Token |
| 358 | lntLastTokLessNL(LNodeTree lnt) |
| 359 | { |
| 360 | int n; |
| 361 | Token tok; |
| 362 | |
| 363 | if (!lnt) return 0; |
| 364 | |
| 365 | switch (lnt->kind) { |
| 366 | case LN_1Tok: |
| 367 | case LN_NTok: |
| 368 | for (n = lnt->argc; n > 0; n--) { |
| 369 | tok = lnt->argv[n-1].tok; |
| 370 | if (!tokIs(tok, KW_NewLine)((tok)->tag == (KW_NewLine))) return tok; |
| 371 | } |
| 372 | return 0; |
| 373 | case LN_NNodes: |
| 374 | case LN_DoPile: |
| 375 | for (n = lnt->argc; n > 0; n--) { |
| 376 | tok = lntLastTokLessNL(lnt->argv[n-1].lnode); |
| 377 | if (tok && !tokIs(tok, KW_NewLine)((tok)->tag == (KW_NewLine))) return tok; |
| 378 | } |
| 379 | return 0; |
| 380 | default: |
| 381 | NotReached(return 0){(void)bug("Not supposed to reach line %d in file: %s\n",381, "linear.c");}; |
| 382 | } |
| 383 | } |
| 384 | |
| 385 | /***************************************************************************** |
| 386 | * |
| 387 | * :: Convert LNodeTree -> TokenList |
| 388 | * |
| 389 | ****************************************************************************/ |
| 390 | |
| 391 | localstatic TokenList |
| 392 | lntToTokenList(LNodeTree lnt) |
| 393 | { |
| 394 | return listNReverse(Token)(Token_listPointer->NReverse)(lntToTokenList0(lnt, NULL((void*)0))); |
| 395 | } |
| 396 | |
| 397 | localstatic TokenList |
| 398 | lntToTokenList0(LNodeTree lnt, TokenList rsofar) |
| 399 | { |
| 400 | int i, n; |
| 401 | |
| 402 | if (!lnt) return rsofar; |
| 403 | |
| 404 | n = lnt->argc; |
| 405 | |
| 406 | switch (lnt->kind) { |
| 407 | case LN_1Tok: |
| 408 | rsofar = listCons(Token)(Token_listPointer->Cons)(lnt->argv[0].tok, rsofar); |
| 409 | break; |
| 410 | case LN_NTok: |
| 411 | for (i = 0; i < n; i++) |
| 412 | rsofar = listCons(Token)(Token_listPointer->Cons)(lnt->argv[i].tok, rsofar); |
| 413 | break; |
| 414 | case LN_NNodes: |
| 415 | for (i = 0; i < n; i++) |
| 416 | rsofar = lntToTokenList0(lnt->argv[i].lnode, rsofar); |
| 417 | break; |
| 418 | case LN_DoPile: |
| 419 | /* Insert newlines between each pair of args. */ |
| 420 | rsofar = lntToTokenList0(lnt->argv[0].lnode, rsofar); |
| 421 | rsofar = lntConsNL(rsofar); |
| 422 | for (i = 1; i < n-1; i++) { |
| 423 | rsofar = lntToTokenList0(lnt->argv[i].lnode, rsofar); |
| 424 | rsofar = lntConsNL(rsofar); |
| 425 | } |
| 426 | rsofar = lntToTokenList0(lnt->argv[n-1].lnode, rsofar); |
| 427 | break; |
| 428 | } |
| 429 | |
| 430 | return rsofar; |
| 431 | } |
| 432 | |
| 433 | localstatic TokenList |
| 434 | lntConsNL(TokenList tl) |
| 435 | { |
| 436 | Token nl = linKeyword(tl ? car(tl)((tl)->first) : 0, KW_NewLine); |
| 437 | |
| 438 | return listCons(Token)(Token_listPointer->Cons)(nl, tl); |
| 439 | } |
| 440 | |
| 441 | /***************************************************************************** |
| 442 | * |
| 443 | * :: Convert TokenList -> LNodeTree |
| 444 | * |
| 445 | ****************************************************************************/ |
| 446 | |
| 447 | /* |
| 448 | * Use a recursive descent parser to convert from lists to trees. |
| 449 | */ |
| 450 | localstatic LNodeTree lntFrTL_DoPile (TokenList *); |
| 451 | localstatic LNodeTree lntFrTL_DoLine (TokenList *); |
| 452 | localstatic LNodeTree lntFrTL_DontPile (TokenList *); |
| 453 | localstatic LNodeTree lntFrTL_DontLine (TokenList *, Bool isStacking); |
| 454 | localstatic LNodeTree lntFrTL_1Tok (TokenList *); |
| 455 | localstatic LNodeTree lntFrTL_MakeLine (LNodeTreeList,int,Length,Length); |
| 456 | |
| 457 | localstatic int depthDoPileNo; |
| 458 | localstatic int depthDontPileNo; |
| 459 | |
| 460 | /* Top-level entry-point for converting token lists into lnode trees */ |
| 461 | localstatic LNodeTree |
| 462 | lntFrTokenList(TokenList tl) |
| 463 | { |
| 464 | depthDoPileNo = 0; |
| 465 | depthDontPileNo = 0; |
| 466 | |
| 467 | return lntFrTL_DontLine(&tl, false((int) 0)); |
| 468 | } |
| 469 | |
| 470 | /* |
| 471 | * Convert a list of tokens for a piled section of code into a tree. If |
| 472 | * the end of the stream is reached without finding a closing #endpile |
| 473 | * then one is automatically added. The first child of the result tree |
| 474 | * is the #pile token and the last is a #endpile token. The other nodes |
| 475 | * correspond to complete lines from source code or embedded piled or |
| 476 | * non-piled sections blocks. |
| 477 | */ |
| 478 | localstatic LNodeTree |
| 479 | lntFrTL_DoPile(TokenList *ptl) |
| 480 | { |
| 481 | TokenList tl0 = *ptl; |
| 482 | LNodeTreeList ll, l; |
| 483 | LNodeTree lnt; |
| 484 | Token tk; |
| 485 | int i, n, in0; |
| 486 | Bool has; |
| 487 | |
| 488 | assert(tl0)do { if (!(tl0)) _do_assert(("tl0"),"linear.c",488); } while ( 0); |
| 489 | assert(tokTag(car(tl0)) == DoPileStart)do { if (!(((TokenTag) (((tl0)->first))->tag) == KW_StartPile )) _do_assert(("tokTag(car(tl0)) == DoPileStart"),"linear.c", 489); } while (0); |
| 490 | |
| 491 | depthDoPileNo += 1; |
| 492 | in0 = linIndentation(tl0); |
| 493 | ll = listCons(LNodeTree)(LNodeTree_listPointer->Cons)(lntFrTL_1Tok(&tl0), NULL((void*)0)); |
| 494 | n = 1; |
| 495 | |
| 496 | while (tl0 && tokTag(car(tl0))((TokenTag) (((tl0)->first))->tag) != DoPileEndKW_EndPile) { |
| 497 | lnt = lntFrTL_DoLine(&tl0); |
| 498 | ll = listCons(LNodeTree)(LNodeTree_listPointer->Cons)(lnt, ll); |
| 499 | n++; |
| 500 | } |
| 501 | if (tl0 && tokTag(car(tl0))((TokenTag) (((tl0)->first))->tag) == DoPileEndKW_EndPile) { |
| 502 | ll = listCons(LNodeTree)(LNodeTree_listPointer->Cons)(lntFrTL_1Tok(&tl0), ll); |
| 503 | n++; |
| 504 | } |
| 505 | /* Insert extra #endpile if needed. */ |
| 506 | else if (!tl0) { |
| 507 | tk = tokKeyword(sposNone, sposNone, DoPileEnd)tokNew(sposNone, sposNone, KW_EndPile); |
| 508 | ll = listCons(LNodeTree)(LNodeTree_listPointer->Cons)(lntTok(tk), ll); |
| 509 | n++; |
| 510 | } |
| 511 | |
| 512 | lnt = lntNewEmpty(LN_DoPile, n); |
| 513 | has = 0; |
| 514 | for (i = n-1, l = ll; i >= 0 ; i--, l = cdr(l)((l)->rest)) { |
| 515 | lnt->argv[i].lnode = car(l)((l)->first); |
| 516 | has |= car(l)((l)->first)->has; |
| 517 | } |
| 518 | lnt->indent = in0; |
| 519 | lnt->has = has; |
| 520 | |
| 521 | *ptl = tl0; |
| 522 | listFree(LNodeTree)(LNodeTree_listPointer->Free)(ll); |
| 523 | depthDoPileNo -= 1; |
| 524 | return lnt; |
| 525 | } |
| 526 | |
| 527 | |
| 528 | /* |
| 529 | * Convert a list of tokens for a single line of code into a tree. If a |
| 530 | * #pile token is found then the embedded piled section is converted into |
| 531 | * a single tree node; likewise for embedded non-piled sections. All |
| 532 | * other tokens are added to the result tree as leaves. Processing stops |
| 533 | * when a newline token is found, the end of the token stream is reached, |
| 534 | * or when a #endpile or } token is found without a matching #pile or {. |
| 535 | */ |
| 536 | localstatic LNodeTree |
| 537 | lntFrTL_DoLine(TokenList *ptl) |
| 538 | { |
| 539 | TokenList tl0 = *ptl; |
| 540 | TokenTag tag; |
| 541 | LNodeTreeList ll; |
| 542 | LNodeTree lnt; |
| 543 | int n, ntoks, in0; |
| 544 | |
| 545 | if (!tl0) { |
| 546 | lnt = lntNewEmpty(LN_NTok, int0((int) 0)); |
| 547 | lnt->indent = 0; |
| 548 | lnt->has = 0; |
| 549 | return lnt; |
| 550 | } |
| 551 | |
| 552 | in0 = linIndentation(tl0); |
| 553 | ll = 0; |
| 554 | n = 0; |
| 555 | ntoks = 0; |
| 556 | |
| 557 | /* This test always succeeds and is therefore redundant */ |
| 558 | if (tl0) do { |
| 559 | tag = tokTag(car(tl0))((TokenTag) (((tl0)->first))->tag); |
| 560 | |
| 561 | switch (tag) { |
| 562 | case DoPileStartKW_StartPile: |
| 563 | lnt = lntFrTL_DoPile(&tl0); |
| 564 | ll = listCons(LNodeTree)(LNodeTree_listPointer->Cons)(lnt, ll); |
| 565 | n++; |
| 566 | break; |
| 567 | case DontPileStartKW_OCurly: |
| 568 | lnt = lntFrTL_DontPile(&tl0); |
| 569 | ll = listCons(LNodeTree)(LNodeTree_listPointer->Cons)(lnt, ll); |
| 570 | n++; |
| 571 | break; |
| 572 | case DoPileEndKW_EndPile: |
| 573 | case DontPileEndKW_CCurly: |
| 574 | if (tag == DoPileEndKW_EndPile) |
| 575 | #if 1 |
| 576 | break; /*XXXXXXX*/ |
| 577 | #else |
| 578 | if (depthDoPileNo) |
| 579 | break; |
| 580 | else if (depthDontPileNo) |
| 581 | break; |
| 582 | #endif |
| 583 | /* Fall through */ |
| 584 | default: |
| 585 | lnt = lntFrTL_1Tok(&tl0); |
| 586 | ll = listCons(LNodeTree)(LNodeTree_listPointer->Cons)(lnt, ll); |
| 587 | n++; |
| 588 | ntoks++; |
| 589 | break; |
| 590 | } |
| 591 | } while (tag != KW_NewLine && |
| 592 | (tag != DoPileEndKW_EndPile || depthDoPileNo == 0) && |
| 593 | (tag != DontPileEndKW_CCurly || depthDontPileNo == 0) && |
| 594 | tl0); |
| 595 | |
| 596 | lnt = lntFrTL_MakeLine(ll, in0, n, ntoks); |
| 597 | *ptl = tl0; |
| 598 | listFree(LNodeTree)(LNodeTree_listPointer->Free)(ll); |
| 599 | return lnt; |
| 600 | } |
| 601 | |
| 602 | /* |
| 603 | * Convert a list of tokens for a non-piled section into an lnode tree. |
| 604 | * For correctly balanced programs the result tree will have three child |
| 605 | * nodes: the first will be a { leaf and the third will be a } leaf. The |
| 606 | * second node will contain all tokens within the non-piled section with |
| 607 | * the nesting of non-piled sections removed. Piled sections will have |
| 608 | * their own tree nodes as normal. |
| 609 | */ |
| 610 | localstatic LNodeTree |
| 611 | lntFrTL_DontPile(TokenList *ptl) |
| 612 | { |
| 613 | TokenList tl0 = *ptl; |
| 614 | LNodeTreeList ll, l; |
| 615 | LNodeTree lnt; |
| 616 | int i, n, in0; |
| 617 | Bool has; |
| 618 | |
| 619 | assert(tl0)do { if (!(tl0)) _do_assert(("tl0"),"linear.c",619); } while ( 0); |
| 620 | assert(tokTag(car(tl0)) == DontPileStart)do { if (!(((TokenTag) (((tl0)->first))->tag) == KW_OCurly )) _do_assert(("tokTag(car(tl0)) == DontPileStart"),"linear.c" ,620); } while (0); |
| 621 | |
| 622 | depthDontPileNo += 1; |
| 623 | in0 = linIndentation(tl0); |
| 624 | ll = listCons(LNodeTree)(LNodeTree_listPointer->Cons)(lntFrTL_1Tok(&tl0), NULL((void*)0)); |
| 625 | ll = listCons(LNodeTree)(LNodeTree_listPointer->Cons)(lntFrTL_DontLine(&tl0, true1), ll); |
| 626 | n = 2; |
| 627 | if (tl0 && tokTag(car(tl0))((TokenTag) (((tl0)->first))->tag) == DontPileEndKW_CCurly) { |
| 628 | ll = listCons(LNodeTree)(LNodeTree_listPointer->Cons)(lntFrTL_1Tok(&tl0), ll); |
| 629 | n++; |
| 630 | } |
| 631 | |
| 632 | lnt = lntNewEmpty(LN_NNodes, n); |
| 633 | has = 0; |
| 634 | for (i = n-1, l = ll; i >= 0 ; i--, l = cdr(l)((l)->rest)) { |
| 635 | lnt->argv[i].lnode = car(l)((l)->first); |
| 636 | has |= car(l)((l)->first)->has; |
| 637 | } |
| 638 | lnt->indent = in0; |
| 639 | lnt->has = has; |
| 640 | |
| 641 | *ptl = tl0; |
| 642 | listFree(LNodeTree)(LNodeTree_listPointer->Free)(ll); |
| 643 | depthDontPileNo -= 1; |
| 644 | return lnt; |
| 645 | } |
| 646 | |
| 647 | /* |
| 648 | * Convert a list of tokens in a non-piled section into a tree. If the |
| 649 | * isStacking flag is false then every token is placed in the resulting |
| 650 | * tree even if it is not correctly balanced. Otherwise only the tokens |
| 651 | * up to the end of the non-piled section are consumed taking into account |
| 652 | * the balancing of { } around non-piled sections. |
| 653 | */ |
| 654 | localstatic LNodeTree |
| 655 | lntFrTL_DontLine(TokenList *ptl, Bool isStacking) |
| 656 | { |
| 657 | TokenList tl0 = *ptl; |
| 658 | TokenTag tag; |
| 659 | LNodeTreeList ll; |
| 660 | LNodeTree lnt; |
| 661 | int n, ntoks, in0, depth; |
| 662 | |
| 663 | if (!tl0) { |
| 664 | lnt = lntNewEmpty(LN_NTok, int0((int) 0)); |
| 665 | lnt->indent = 0; |
| 666 | lnt->has = 0; |
| 667 | return lnt; |
| 668 | } |
| 669 | |
| 670 | in0 = linIndentation(tl0); |
| 671 | depth = 0; |
| 672 | n = 0; |
| 673 | ntoks = 0; |
| 674 | ll = 0; |
| 675 | |
| 676 | while (tl0) { |
| 677 | tag = tokTag(car(tl0))((TokenTag) (((tl0)->first))->tag); |
| 678 | |
| 679 | if (tag == DoPileStartKW_StartPile) { |
| 680 | lnt = lntFrTL_DoPile(&tl0); |
| 681 | ll = listCons(LNodeTree)(LNodeTree_listPointer->Cons)(lnt, ll); |
| 682 | n++; |
| 683 | } |
| 684 | else { |
| 685 | if (isStacking && tag == DontPileStartKW_OCurly) { |
| 686 | depth++; |
| 687 | } |
| 688 | if (isStacking && tag == DontPileEndKW_CCurly) { |
| 689 | depth--; |
| 690 | } |
| 691 | if (depth < 0) break; |
| 692 | |
| 693 | lnt = lntFrTL_1Tok(&tl0); |
| 694 | ll = listCons(LNodeTree)(LNodeTree_listPointer->Cons)(lnt, ll); |
| 695 | n++; |
| 696 | ntoks++; |
| 697 | } |
| 698 | } |
| 699 | |
| 700 | lnt = lntFrTL_MakeLine(ll, in0, n, ntoks); |
| 701 | *ptl = tl0; |
| 702 | listFree(LNodeTree)(LNodeTree_listPointer->Free)(ll); |
| 703 | return lnt; |
| 704 | } |
| 705 | |
| 706 | |
| 707 | /* Remove a token from the token list and convert into an lnode tree leaf */ |
| 708 | localstatic LNodeTree |
| 709 | lntFrTL_1Tok(TokenList *ptl) |
| 710 | { |
| 711 | LNodeTree lnt; |
| 712 | |
| 713 | assert(*ptl)do { if (!(*ptl)) _do_assert(("*ptl"),"linear.c",713); } while (0); |
| 714 | |
| 715 | lnt = lntTok(car(*ptl)((*ptl)->first)); |
| 716 | *ptl = cdr(*ptl)((*ptl)->rest); |
| 717 | |
| 718 | return lnt; |
| 719 | } |
| 720 | |
| 721 | /* Convert a list of tree nodes into a single n-ary tree node */ |
| 722 | localstatic LNodeTree |
| 723 | lntFrTL_MakeLine(LNodeTreeList ll, int in0, Length n, Length ntoks) |
| 724 | { |
| 725 | int i; |
| 726 | LNodeTreeList l; |
| 727 | LNodeTree lnt; |
| 728 | Bool has; |
| 729 | |
| 730 | has = 0; |
| 731 | for (l = ll; l; l = cdr(l)((l)->rest)) |
| 732 | has |= car(l)((l)->first)->has; |
| 733 | |
| 734 | if (n == 1) { |
| 735 | lnt = car(ll)((ll)->first); |
| 736 | } |
| 737 | else if (n == ntoks) { |
| 738 | /* |
| 739 | * Compactify the case when all subtrees are tokens. |
| 740 | */ |
| 741 | lnt = lntNewEmpty(LN_NTok, n); |
| 742 | lnt->indent = in0; |
| 743 | lnt->has = has; |
| 744 | |
| 745 | for (i = n-1, l = ll; i >= 0; i--, l = cdr(l)((l)->rest)) { |
| 746 | lnt->argv[i].tok = car(l)((l)->first)->argv[0].tok; |
| 747 | lntFree(car(l)((l)->first)); |
| 748 | } |
| 749 | } |
| 750 | else { |
| 751 | lnt = lntNewEmpty(LN_NNodes, n); |
| 752 | lnt->indent = in0; |
| 753 | lnt->has = has; |
| 754 | |
| 755 | for (i = n-1, l = ll; i >= 0; i--, l = cdr(l)((l)->rest)) |
| 756 | lnt->argv[i].lnode = car(l)((l)->first); |
| 757 | } |
| 758 | |
| 759 | return lnt; |
| 760 | } |
| 761 | |
| 762 | |
| 763 | /**************************************************************************** |
| 764 | * |
| 765 | * :: Verify balance of piling braces |
| 766 | * |
| 767 | ***************************************************************************/ |
| 768 | |
| 769 | # define LIN_NOT_OK0 0 |
| 770 | # define LIN_OK1 1 |
| 771 | |
| 772 | localstatic void |
| 773 | serrorUnbalanced(Token tok,Bool errorIfTrue) |
| 774 | { |
| 775 | SrcPos pos = tok->pos; |
| 776 | TokenTag tag = tokTag(tok)((TokenTag) (tok)->tag), mate = tokTag(tok)((TokenTag) (tok)->tag); |
Value stored to 'mate' during its initialization is never read | |
| 777 | |
| 778 | switch (tag) { |
| 779 | case DoPileStartKW_StartPile: mate = DoPileEndKW_EndPile; break; |
| 780 | case DoPileEndKW_EndPile: mate = DoPileStartKW_StartPile; break; |
| 781 | case DontPileStartKW_OCurly: mate = DontPileEndKW_CCurly; break; |
| 782 | case DontPileEndKW_CCurly: mate = DontPileStartKW_OCurly; break; |
| 783 | default: comsgFatal(abNewNothing(pos)abNew(AB_Nothing, pos,0 ), ALDOR_F_Bug365, |
| 784 | "unexpected unbalanced token"); |
| 785 | } |
| 786 | |
| 787 | if (errorIfTrue) { |
| 788 | comsgError(abNewNothing(pos)abNew(AB_Nothing, pos,0 ), ALDOR_E_LinUnbalanced70, |
| 789 | keyString(tag), keyString(mate)); |
| 790 | } |
| 791 | else { |
| 792 | comsgWarning(abNewNothing(pos)abNew(AB_Nothing, pos,0 ), ALDOR_E_LinUnbalanced70, |
| 793 | keyString(tag), keyString(mate)); |
| 794 | } |
| 795 | } |
| 796 | |
| 797 | /* |
| 798 | * Look for unmatched {,},{|,|} and give error msg. |
| 799 | * It also sets tok->extra field for each token in the token list. |
| 800 | */ |
| 801 | localstatic void |
| 802 | linCheckBalance0(TokenList *ptl, Token lastOpener, int depth) |
| 803 | { |
| 804 | TokenTag tag; |
| 805 | Token tok; |
| 806 | |
| 807 | linDEBUGif (!linDebug) { } else afprintf(dbOut, "->> linCheckPile0: %d--\n", tokTag(lastOpener)((TokenTag) (lastOpener)->tag)); |
| 808 | |
| 809 | lastOpener->extra = LIN_OK1; |
| 810 | |
| 811 | while (*ptl) { |
| 812 | tok = car(*ptl)((*ptl)->first); |
| 813 | tag = tokTag(tok)((TokenTag) (tok)->tag); |
| 814 | *ptl = cdr(*ptl)((*ptl)->rest); |
| 815 | |
| 816 | switch(tag) { |
| 817 | case DoPileStartKW_StartPile: |
| 818 | case DontPileStartKW_OCurly: |
| 819 | linCheckBalance0(ptl, tok, depth+1); |
| 820 | break; |
| 821 | case DoPileEndKW_EndPile: |
| 822 | if (tokTag(lastOpener)((TokenTag) (lastOpener)->tag) == DoPileStartKW_StartPile) { |
| 823 | tok->extra = LIN_OK1; |
| 824 | linDEBUGif (!linDebug) { } else afprintf(dbOut, "-<< linCheckPile0- |} --\n"); |
| 825 | return; |
| 826 | } |
| 827 | else { |
| 828 | tok->extra = LIN_NOT_OK0; |
| 829 | serrorUnbalanced(tok,true1); |
| 830 | } |
| 831 | break; |
| 832 | case DontPileEndKW_CCurly: |
| 833 | if (tokTag(lastOpener)((TokenTag) (lastOpener)->tag) == DontPileStartKW_OCurly) { |
| 834 | tok->extra = LIN_NOT_OK0; |
| 835 | linDEBUGif (!linDebug) { } else afprintf(dbOut, "-<< linCheckPile0- } --\n"); |
| 836 | return; |
| 837 | } |
| 838 | else { |
| 839 | tok->extra = LIN_NOT_OK0; |
| 840 | serrorUnbalanced(tok,true1); |
| 841 | } |
| 842 | break; |
| 843 | default: |
| 844 | break; |
| 845 | } |
| 846 | } |
| 847 | |
| 848 | /* Detect unmatched opener, but allow missing #endpile at top level.*/ |
| 849 | tag = tokTag(lastOpener)((TokenTag) (lastOpener)->tag); |
| 850 | if (tag != TK_Blank && tag != DoPileStartKW_StartPile ) { |
| 851 | lastOpener->extra = LIN_NOT_OK0; |
| 852 | serrorUnbalanced(lastOpener,true1); |
| 853 | } |
| 854 | if (tag != TK_Blank && depth > 1 ) { |
| 855 | lastOpener->extra = LIN_NOT_OK0; |
| 856 | serrorUnbalanced(lastOpener,false((int) 0)); |
| 857 | } |
| 858 | linDEBUGif (!linDebug) { } else afprintf(dbOut, "-<< linCheckPile0-NULL--\n"); |
| 859 | } |
| 860 | |
| 861 | |
| 862 | /* |
| 863 | * This function returns the original list but we should suppose that |
| 864 | * it could be different -- we may later insert correction tokens. |
| 865 | */ |
| 866 | localstatic TokenList |
| 867 | linCheckBalance(TokenList tl0) |
| 868 | { |
| 869 | TokenList tl = tl0; |
| 870 | Token tok; |
| 871 | |
| 872 | /* Mark all nodes OK. */ |
| 873 | for (tl = tl0; tl; tl = cdr(tl)((tl)->rest)) |
| 874 | car(tl)((tl)->first)->extra = LIN_OK1; |
| 875 | |
| 876 | /* Do the balancing act. */ |
| 877 | tl = tl0; |
| 878 | tok = tokNew(sposNone, sposNone, TK_Blank, NULL((void*)0)); |
| 879 | linCheckBalance0(&tl, tok, int0((int) 0)); |
| 880 | tokFree(tok); |
| 881 | |
| 882 | return tl0; |
| 883 | } |
| 884 | |
| 885 | /***************************************************************************** |
| 886 | * |
| 887 | * :: Main entry point of linearizer |
| 888 | * |
| 889 | ****************************************************************************/ |
| 890 | |
| 891 | TokenList |
| 892 | linearize(TokenList tl) |
| 893 | { |
| 894 | LNodeTree lnt; |
| 895 | |
| 896 | if (DEBUG(lin)linDebug) { |
| 897 | fprintf(dbOut,"-------------- Starting with -------------\n"); |
| 898 | toklistPrint(dbOut, tl); |
| 899 | fnewline(dbOut); |
| 900 | } |
| 901 | |
| 902 | tl = linXComments(tl)linXTokens((tl), TK_Comment); |
| 903 | tl = linXBlankLines(tl); |
| 904 | |
| 905 | /* Add a `#pile' if in interactive mode, so that the user can use |
| 906 | * TAB for an easier input. |
| 907 | */ |
| 908 | |
| 909 | if (fintMode == FINT_LOOP2) { |
| 910 | Token tok = tokNew(sposNone, sposNone, KW_StartPile, NULL((void*)0)); |
| 911 | listPush(Token, tok, tl)(tl = (Token_listPointer->Cons)(tok, tl)); |
| 912 | } |
| 913 | |
| 914 | tl = linCheckBalance(tl); |
| 915 | lnt = lntFrTokenList(tl); |
| 916 | listFree(Token)(Token_listPointer->Free)(tl); |
| 917 | if (DEBUG(lin)linDebug) { |
| 918 | fprintf(dbOut,"-------------- Converted to --------------\n"); |
| 919 | lntPrint(dbOut, lnt); |
| 920 | fnewline(dbOut); |
| 921 | } |
| 922 | |
| 923 | lnt = lin2DRules(lnt); |
| 924 | if (DEBUG(lin)linDebug) { |
| 925 | fprintf(dbOut,"-------------- Converted to -------------\n"); |
| 926 | lntPrint(dbOut, lnt); |
| 927 | fnewline(dbOut); |
| 928 | } |
| 929 | |
| 930 | tl = lntToTokenList(lnt); |
| 931 | tl = linXNewLines(tl)linXTokens((tl), KW_NewLine); |
| 932 | lntFree(lnt); |
| 933 | if (DEBUG(lin)linDebug) { |
| 934 | fprintf(dbOut,"-------------- Ending with -------------\n"); |
| 935 | toklistPrint(dbOut, tl); |
| 936 | fnewline(dbOut); |
| 937 | } |
| 938 | |
| 939 | tl = linUseNeededSep(tl); |
| 940 | |
| 941 | if (DEBUG(lin)linDebug) { |
| 942 | fprintf(dbOut,"-------------- Leaving with ------------\n"); |
| 943 | toklistPrint(dbOut, tl); |
| 944 | fnewline(dbOut); |
| 945 | } |
| 946 | |
| 947 | return tl; |
| 948 | } |
| 949 | |
| 950 | /* This function inserts or deletes statement separators (;) as required */ |
| 951 | localstatic TokenList |
| 952 | linUseNeededSep(TokenList tl) |
| 953 | { |
| 954 | tl = linISepAfterDontPiles(tl); |
| 955 | |
| 956 | if (DEBUG(lin)linDebug) { |
| 957 | fprintf(dbOut,"------- linUseNeededSep (mid) ----------\n"); |
| 958 | toklistPrint(dbOut, tl); |
| 959 | fnewline(dbOut); |
| 960 | } |
| 961 | |
| 962 | tl = linXSep(tl); |
| 963 | |
| 964 | if (DEBUG(lin)linDebug) { |
| 965 | fprintf(dbOut,"------- linUseNeededSep (xit) ----------\n"); |
| 966 | toklistPrint(dbOut, tl); |
| 967 | fnewline(dbOut); |
| 968 | } |
| 969 | return tl; |
| 970 | } |
| 971 | |
| 972 | /***************************************************************************** |
| 973 | * |
| 974 | * :: TokenList Utilities |
| 975 | * |
| 976 | ****************************************************************************/ |
| 977 | |
| 978 | localstatic Token |
| 979 | linKeyword(Token org, TokenTag key) |
| 980 | { |
| 981 | SrcPos spos = org ? org->pos : sposNone; |
| 982 | SrcPos epos = org ? org->end : sposNone; |
| 983 | |
| 984 | return tokKeyword(spos, epos, key)tokNew(spos, epos, key); |
| 985 | } |
| 986 | |
| 987 | /* |
| 988 | * Free the specified tokens. (Modifies the original list.) |
| 989 | */ |
| 990 | localstatic TokenList |
| 991 | linXTokens(TokenList tl, TokenTag tag) |
| 992 | { |
| 993 | struct TokenListCons head; |
| 994 | TokenList prev; |
| 995 | |
| 996 | setcar(&head, NULL)((&head)->first = (((void*)0))); |
| 997 | setcdr(&head, tl)((&head)->rest = (tl)); |
| 998 | |
| 999 | for (prev = &head; cdr(prev)((prev)->rest); ) { |
| 1000 | TokenList curr = cdr(prev)((prev)->rest); |
| 1001 | Token tok = car(curr)((curr)->first); |
| 1002 | |
| 1003 | if (tokTag(tok)((TokenTag) (tok)->tag) == tag) { |
| 1004 | setcdr(prev, cdr(curr))((prev)->rest = (((curr)->rest))); |
| 1005 | listFreeCons(Token)(Token_listPointer->FreeCons)(curr); |
| 1006 | tokFree(tok); |
| 1007 | } |
| 1008 | else |
| 1009 | prev = curr; |
| 1010 | } |
| 1011 | return cdr(&head)((&head)->rest); |
| 1012 | } |
| 1013 | |
| 1014 | /* |
| 1015 | * Free leading newlines and all but the first of consecutive newlines. |
| 1016 | * (Modifies the original list.) |
| 1017 | */ |
| 1018 | localstatic TokenList |
| 1019 | linXBlankLines0(TokenList tl) |
| 1020 | { |
| 1021 | while (tl && tokTag(car(tl))((TokenTag) (((tl)->first))->tag) == KW_NewLine) { |
| 1022 | Token tk = car(tl)((tl)->first); |
| 1023 | TokenList rl = cdr(tl)((tl)->rest); |
| 1024 | |
| 1025 | tokFree(tk); |
| 1026 | listFreeCons(Token)(Token_listPointer->FreeCons)(tl); |
| 1027 | tl = rl; |
| 1028 | } |
| 1029 | return tl; |
| 1030 | } |
| 1031 | |
| 1032 | localstatic TokenList |
| 1033 | linXBlankLines(TokenList tl0) |
| 1034 | { |
| 1035 | TokenList tl; |
| 1036 | |
| 1037 | tl0 = linXBlankLines0(tl0); |
| 1038 | |
| 1039 | for (tl = tl0; tl; tl = cdr(tl)((tl)->rest)) { |
| 1040 | Token tok = car(tl)((tl)->first); |
| 1041 | TokenList rest = cdr(tl)((tl)->rest); |
| 1042 | |
| 1043 | if (tokTag(tok)((TokenTag) (tok)->tag) == KW_NewLine || tokTag(tok)((TokenTag) (tok)->tag) == DoPileStartKW_StartPile) { |
| 1044 | /* !!!FIXME!!! Loop executes just once? */ |
| 1045 | while (rest && tokTag(car(rest))((TokenTag) (((rest)->first))->tag) == KW_NewLine) |
| 1046 | rest = linXBlankLines0(rest); |
| 1047 | setcdr(tl, rest)((tl)->rest = (rest)); |
| 1048 | } |
| 1049 | } |
| 1050 | return tl0; |
| 1051 | } |
| 1052 | |
| 1053 | |
| 1054 | /* |
| 1055 | * Insert ";" after all "}". (Modifies the original list.) This function |
| 1056 | * ought to be modified to use a two-token look-ahead. If the next token |
| 1057 | * is not DontPileSep and the one after is not a follower or a closer |
| 1058 | * then the insertion can take place. If this change is made then linXSep |
| 1059 | * is redundant and the compiler will make fewer strange parsing decisions. |
| 1060 | */ |
| 1061 | localstatic TokenList |
| 1062 | linISepAfterDontPiles(TokenList tl) |
| 1063 | { |
| 1064 | TokenList t; |
| 1065 | for (t = tl; t; t = cdr(t)((t)->rest)) { |
| 1066 | if (tokIs(car(t), DontPileEnd)((((t)->first))->tag == (KW_CCurly))) { |
| 1067 | TokenList trest = cdr(t)((t)->rest); |
| 1068 | |
| 1069 | if (trest && !tokIs(car(trest), DontPileSep)((((trest)->first))->tag == (KW_Semicolon))) { |
| 1070 | Token tok = linKeyword(car(t)((t)->first),DontPileSepKW_Semicolon); |
| 1071 | trest = listCons(Token)(Token_listPointer->Cons)(tok, trest); |
| 1072 | setcdr(t, trest)((t)->rest = (trest)); |
| 1073 | } |
| 1074 | } |
| 1075 | } |
| 1076 | |
| 1077 | return tl; |
| 1078 | } |
| 1079 | |
| 1080 | /* |
| 1081 | * Delete ";" before non-starters. This function would be redundant if |
| 1082 | * linISepAfterDontPiles() used a two-token look-ahead. |
| 1083 | */ |
| 1084 | localstatic TokenList |
| 1085 | linXSep(TokenList tl) |
| 1086 | { |
| 1087 | TokenList t; |
| 1088 | |
| 1089 | /* Delete leading string ";". */ |
| 1090 | while (tl && tokIs(car(tl), DontPileSep)((((tl)->first))->tag == (KW_Semicolon))) |
| 1091 | tl = listFreeDeeplyTo(Token)(Token_listPointer->FreeDeeplyTo)(tl,cdr(tl)((tl)->rest),tokFree); |
| 1092 | |
| 1093 | /* Delete ";" before non-starters. */ |
| 1094 | for (t = tl; t; t = cdr(t)((t)->rest)) { |
| 1095 | TokenList tcdr, tcddr; |
| 1096 | tcdr = cdr(t)((t)->rest); |
| 1097 | if (!tcdr) break; |
| 1098 | if (!tokIs(car(tcdr), DontPileSep)((((tcdr)->first))->tag == (KW_Semicolon))) continue; |
| 1099 | tcddr = cdr(tcdr)((tcdr)->rest); |
| 1100 | if (!tcddr || tokIsNonStarter(car(tcddr))(((tokInfoTable[((((tcddr)->first))->tag)-TK_START]).isFollower ) || ((tokInfoTable[((((tcddr)->first))->tag)-TK_START] ).isCloser))) |
| 1101 | setcdr(t, listFreeDeeplyTo(Token)(tcdr,tcddr,tokFree))((t)->rest = ((Token_listPointer->FreeDeeplyTo)(tcdr,tcddr ,tokFree))); |
| 1102 | } |
| 1103 | |
| 1104 | return tl; |
| 1105 | } |
| 1106 | |
| 1107 | /* |
| 1108 | * Determine the true indentation a line, taking into account labels. |
| 1109 | */ |
| 1110 | localstatic int |
| 1111 | linIndentation(TokenList tl) |
| 1112 | { |
| 1113 | int ind; |
| 1114 | |
| 1115 | if (DEBUG(lin)linDebug) { |
| 1116 | if (tl) |
| 1117 | tokPrint(dbOut, car(tl)((tl)->first)); |
| 1118 | } |
| 1119 | |
| 1120 | if (tl && tokIs(car(tl), KW_At)((((tl)->first))->tag == (KW_At))) { |
| 1121 | /* Skip '@' and 'id' if there. */ |
| 1122 | tl = cdr(tl)((tl)->rest); |
| 1123 | if (tl) tl = cdr(tl)((tl)->rest); |
| 1124 | } |
| 1125 | ind = tl && !tokIs(car(tl), KW_NewLine)((((tl)->first))->tag == (KW_NewLine)) |
| 1126 | ? sposChar(car(tl)((tl)->first)->pos) |
| 1127 | : MootIndentation(-1); |
| 1128 | |
| 1129 | phaseDEBUGif (!phaseDebug) { } else afprintf(dbOut, " line indented to: %d\n", ind); |
| 1130 | |
| 1131 | return ind; |
| 1132 | } |
| 1133 | |
| 1134 | /**************************************************************************** |
| 1135 | * |
| 1136 | * :: Apply piling rules. |
| 1137 | * |
| 1138 | ****************************************************************************/ |
| 1139 | |
| 1140 | localstatic LNodeTree lin2DRulesPile (LNodeTree); |
| 1141 | localstatic LNodeTree lin2DRulesPile0 (LNodeTree context, LNodeTree, int *, int *); |
| 1142 | |
| 1143 | localstatic LNodeTree joinUp (LNodeTree context, LNodeTreeList); |
| 1144 | localstatic Bool isBackSetRequired (LNodeTree context, LNodeTree, LNodeTree); |
| 1145 | localstatic Bool isPileRequired (LNodeTree context, LNodeTree); |
| 1146 | |
| 1147 | localstatic LNodeTree |
| 1148 | lin2DRules(LNodeTree lnt) |
| 1149 | { |
| 1150 | int i, n; |
| 1151 | n = lnt->argc; |
| 1152 | |
| 1153 | switch (lnt->kind) { |
| 1154 | case LN_1Tok: |
| 1155 | case LN_NTok: |
| 1156 | break; |
| 1157 | case LN_NNodes: |
| 1158 | for (i = 0; i < n; i++) |
| 1159 | lnt->argv[i].lnode = lin2DRules(lnt->argv[i].lnode); |
| 1160 | break; |
| 1161 | case LN_DoPile: |
| 1162 | for (i = 0; i < n; i++) |
| 1163 | lnt->argv[i].lnode = lin2DRules(lnt->argv[i].lnode); |
| 1164 | lnt = lin2DRulesPile(lnt); |
| 1165 | break; |
| 1166 | } |
| 1167 | |
| 1168 | return lnt; |
| 1169 | } |
| 1170 | |
| 1171 | #define linIsArgKW(lnt,n,k)((lnt)->argc > (n) && (lnt)->argv[n].lnode-> kind == LN_1Tok && (((lnt)->argv[n].lnode->argv [0].tok)->tag == (k))) \ |
| 1172 | ((lnt)->argc > (n) && (lnt)->argv[n].lnode->kind == LN_1Tok && \ |
| 1173 | tokIs((lnt)->argv[n].lnode->argv[0].tok, k)(((lnt)->argv[n].lnode->argv[0].tok)->tag == (k))) |
| 1174 | |
| 1175 | localstatic LNodeTree |
| 1176 | lin2DRulesPile(LNodeTree lnt) |
| 1177 | { |
| 1178 | Bool hasStarter, hasEnder; |
| 1179 | int iS, iE; |
| 1180 | LNodeTree rnt; |
| 1181 | |
| 1182 | assert(lnt->kind == LN_DoPile)do { if (!(lnt->kind == LN_DoPile)) _do_assert(("lnt->kind == LN_DoPile" ),"linear.c",1182); } while (0); |
| 1183 | |
| 1184 | hasStarter = linIsArgKW(lnt, int0, DoPileStart)((lnt)->argc > (((int) 0)) && (lnt)->argv[(( int) 0)].lnode->kind == LN_1Tok && (((lnt)->argv [((int) 0)].lnode->argv[0].tok)->tag == (KW_StartPile)) ); |
| 1185 | hasEnder = linIsArgKW(lnt, lnt->argc-1, DoPileEnd)((lnt)->argc > (lnt->argc-1) && (lnt)->argv [lnt->argc-1].lnode->kind == LN_1Tok && (((lnt) ->argv[lnt->argc-1].lnode->argv[0].tok)->tag == ( KW_EndPile))); |
| 1186 | |
| 1187 | iS = hasStarter ? 1 : 0; |
| 1188 | iE = hasStarter && hasEnder ? lnt->argc - 2 : lnt->argc - 1; |
| 1189 | |
| 1190 | /* |
| 1191 | * Consider xxx1 |
| 1192 | * xxx2 |
| 1193 | * xxx3 |
| 1194 | * xxx4 |
| 1195 | * xxx5 |
| 1196 | */ |
| 1197 | |
| 1198 | /* Handle pile starting with first line: xxx1..xxx4 */ |
| 1199 | rnt = lin2DRulesPile0(NULL((void*)0), lnt, &iS, &iE); |
| 1200 | |
| 1201 | /* Handle subsequent outdented piles: e.g., xxx5 */ |
| 1202 | while (iS <= iE) |
| 1203 | rnt = lin2DRulesPile0(rnt, lnt, &iS, &iE); |
| 1204 | |
| 1205 | lntFreeNode(lnt); |
| 1206 | return rnt; |
| 1207 | } |
| 1208 | |
| 1209 | |
| 1210 | /* |
| 1211 | * Piles a range of descendents. Note that since the final argument is |
| 1212 | * never updated it ought to be passed by value. |
| 1213 | */ |
| 1214 | localstatic LNodeTree |
| 1215 | lin2DRulesPile0(LNodeTree context, LNodeTree lnt, int *piS, int *piE) |
| 1216 | { |
| 1217 | int iS = *piS, iE = *piE; |
| 1218 | int indentS, indent0; |
| 1219 | LNodeTree lnt0; |
| 1220 | LNodeTreeList sofar; |
| 1221 | |
| 1222 | phaseDEBUGif (!phaseDebug) { } else afprintf(dbOut, " ==== Linearizing parts %d to %d \n", *piS, *piE); |
| 1223 | |
| 1224 | if (iS > iE) return lntNewEmpty(LN_NNodes, int0((int) 0)); |
| 1225 | |
| 1226 | indentS = lnt->argv[iS].lnode->indent; |
| 1227 | sofar = 0; |
| 1228 | |
| 1229 | phaseDEBUGif (!phaseDebug) { } else afprintf(dbOut, "indentS = %d\n", indentS); |
| 1230 | while (iS <= iE) { |
| 1231 | lnt0 = lnt->argv[iS].lnode; |
| 1232 | indent0 = lnt0->indent; |
| 1233 | |
| 1234 | if (DEBUG(phase)phaseDebug) { |
| 1235 | fprintf(dbOut,"%d/%d/%d. indent0 = %d (argc = %d)\n", |
| 1236 | iS, iE, (int) lnt->argc, |
| 1237 | indent0, (int) lnt0->argc); |
| 1238 | lntPrint(dbOut, lnt0); |
| 1239 | fnewline(dbOut); |
| 1240 | } |
| 1241 | |
| 1242 | if (linIsBlank(lnt0)(!((lnt0)->has & (1<<1))) || indent0 == MootIndentation(-1)) { |
| 1243 | iS++; |
| 1244 | phaseDEBUGif (!phaseDebug) { } else afprintf(dbOut, "Ah.... a blank line _________\n"); |
| 1245 | sofar = listCons(LNodeTree)(LNodeTree_listPointer->Cons)(lnt0, sofar); |
| 1246 | continue; |
| 1247 | } |
| 1248 | |
| 1249 | phaseDEBUGif (!phaseDebug) { } else afprintf(dbOut, "%d :: %d\n", indent0, indentS); |
| 1250 | if (indent0 < indentS) |
| 1251 | break; |
| 1252 | |
| 1253 | if (indent0 == indentS) { |
| 1254 | iS++; |
| 1255 | sofar = listCons(LNodeTree)(LNodeTree_listPointer->Cons)(lnt0, sofar); |
| 1256 | if (DEBUG(phase)phaseDebug) { |
| 1257 | fprintf(dbOut,"Adding one more +++++++++++++ "); |
| 1258 | listPrint(LNodeTree)(LNodeTree_listPointer->Print)(dbOut, sofar, lntPrint); |
| 1259 | fnewline(dbOut); |
| 1260 | } |
| 1261 | } |
| 1262 | /* (indent0 > indentS) */ |
| 1263 | else { |
| 1264 | setcar(sofar, lin2DRulesPile0(car(sofar),lnt,&iS,&iE))((sofar)->first = (lin2DRulesPile0(((sofar)->first),lnt ,&iS,&iE))); |
| 1265 | if (DEBUG(phase)phaseDebug) { |
| 1266 | fprintf(dbOut,"Joining indentee >>>>>>>>>>>> "); |
| 1267 | listPrint(LNodeTree)(LNodeTree_listPointer->Print)(dbOut, sofar, lntPrint); |
| 1268 | fnewline(dbOut); |
| 1269 | } |
| 1270 | } |
| 1271 | } |
| 1272 | sofar = listNReverse(LNodeTree)(LNodeTree_listPointer->NReverse)(sofar); |
| 1273 | lnt0 = lntConcat(context, joinUp(context, sofar)); |
| 1274 | |
| 1275 | if (DEBUG(phase)phaseDebug) { |
| 1276 | fprintf(dbOut,"Result of joinUp is !!!!!!!!!!!!! "); |
| 1277 | lntPrint(dbOut, lnt0); |
| 1278 | fnewline(dbOut); |
| 1279 | } |
| 1280 | |
| 1281 | /* Free the list we just consed. */ |
| 1282 | listFree(LNodeTree)(LNodeTree_listPointer->Free)(sofar); |
| 1283 | *piS = iS; |
| 1284 | *piE = iE; |
| 1285 | return lnt0; |
| 1286 | } |
| 1287 | |
| 1288 | |
| 1289 | /* |
| 1290 | * Insert SetTab .. BackSet .. BackSet ... BackTab |
| 1291 | */ |
| 1292 | localstatic LNodeTree |
| 1293 | joinUp(LNodeTree context, LNodeTreeList tll) |
| 1294 | { |
| 1295 | LNodeTreeList l; |
| 1296 | LNodeTree lnt, t0, t1; |
| 1297 | Bool hadBackSet; |
| 1298 | |
| 1299 | assert(tll != 0)do { if (!(tll != 0)) _do_assert(("tll != 0"),"linear.c",1299 ); } while (0); |
| 1300 | |
| 1301 | /* Insert BackSets between the lines, if necessary. */ |
| 1302 | lnt = car(tll)((tll)->first); |
| 1303 | hadBackSet = false((int) 0); |
| 1304 | |
| 1305 | for (l = tll, t0 = lnt; cdr(l)((l)->rest); l = cdr(l)((l)->rest), t0 = t1) { |
| 1306 | t1 = car(cdr(l))((((l)->rest))->first); |
| 1307 | |
| 1308 | if (isBackSetRequired(context, t0, t1)) { |
| 1309 | hadBackSet = true1; |
| 1310 | lnt = lntSeparate(lnt, KW_BackSet, t1); |
| 1311 | } |
| 1312 | else |
| 1313 | lnt = lntConcat(lnt, t1); |
| 1314 | } |
| 1315 | |
| 1316 | /* Surround with SetTab and BackTab, if necessary. */ |
| 1317 | if (hadBackSet || isPileRequired(context, lnt)) |
| 1318 | lnt = lntWrap(KW_SetTab, lnt, KW_BackTab); |
| 1319 | |
| 1320 | return lnt; |
| 1321 | } |
| 1322 | |
| 1323 | /* |
| 1324 | * "isPileRequired" decides whether a SetTab/BackTab empiling is needed |
| 1325 | * for the line which is to be joined to *pcontext. |
| 1326 | * |
| 1327 | * A single line pile is formed whenever the previous word is an alphabetic |
| 1328 | * language keyword, e.g. "return", "then", "else", etc. |
| 1329 | * (Note, this does not include user-definable operators such as "quo".) |
| 1330 | */ |
| 1331 | localstatic Bool |
| 1332 | isPileRequired(LNodeTree context, LNodeTree lnt) |
| 1333 | { |
| 1334 | /*ARGSUSED*/ |
| 1335 | Token tok = lntLastTokLessNL(context); |
| 1336 | |
| 1337 | phaseDEBUGif (!phaseDebug) { } else afprintf(dbOut,"In isPileRequired %s", |
| 1338 | tok? "with token: " : "NO TOK\n"); |
| 1339 | |
| 1340 | if (!tok) return false((int) 0); |
| 1341 | |
| 1342 | if (DEBUG(phase)phaseDebug) { |
| 1343 | tokPrint(dbOut, tok); |
| 1344 | } |
| 1345 | |
| 1346 | return tokIs(tok, KW_Then)((tok)->tag == (KW_Then)) || tokIs(tok, KW_Else)((tok)->tag == (KW_Else)) || |
| 1347 | tokIs(tok, KW_With)((tok)->tag == (KW_With)) || tokIs(tok, KW_Add)((tok)->tag == (KW_Add)) || |
| 1348 | tokIs(tok, KW_Try)((tok)->tag == (KW_Try)) || tokIs(tok, KW_But)((tok)->tag == (KW_But)) || |
| 1349 | tokIs(tok, KW_Catch)((tok)->tag == (KW_Catch)) || tokIs(tok, KW_Finally)((tok)->tag == (KW_Finally)) || |
| 1350 | tokIs(tok, KW_Always)((tok)->tag == (KW_Always)); |
| 1351 | } |
| 1352 | |
| 1353 | |
| 1354 | /* |
| 1355 | * "isBackSetRequired" decides whether a BackSet is needed between tl1 and tl2. |
| 1356 | * Normally a BackSet is needed. The exceptions are: |
| 1357 | * |
| 1358 | * 1. tl1 contains only ++ comments (-- comments already deleted) |
| 1359 | * This allows |
| 1360 | * |
| 1361 | * ++ xxx |
| 1362 | * f: T -> Y |
| 1363 | * |
| 1364 | * 2. tl1 ends with "," or an opener ("(" "[" etc). |
| 1365 | * This allows |
| 1366 | * |
| 1367 | * f(x, a := [ |
| 1368 | * y, 1, 2, 3, |
| 1369 | * z) 4, 5, 6 ] |
| 1370 | * |
| 1371 | * 3. tl2 begins with "in", "then", "else" or a closer (")" "]" "}" etc) |
| 1372 | * (i.e. words which CANNOT start an expression). |
| 1373 | * This allows |
| 1374 | * |
| 1375 | * if aaa let f(x, a := [1, 2, 3, |
| 1376 | * then bbb f == 1 y 4, 5, 6 |
| 1377 | * else ccc in x := f+f ) ] |
| 1378 | * |
| 1379 | * 4. The lines occur within "{ }" |
| 1380 | * |
| 1381 | * Note: case 4 appears to be ignored and the context is not used. |
| 1382 | */ |
| 1383 | localstatic Bool |
| 1384 | isBackSetRequired(LNodeTree context, LNodeTree lnt1, LNodeTree lnt2) |
| 1385 | { |
| 1386 | /*ARGSUSED*/ |
| 1387 | Token tok1 = lntLastTokLessNL (lnt1); |
| 1388 | Token tok2 = lntFirstTok (lnt2); |
| 1389 | |
| 1390 | if (DEBUG(phase)phaseDebug) { |
| 1391 | fprintf(dbOut,"In isBackSetRequrired "); |
| 1392 | fprintf(dbOut,"First tree "); |
| 1393 | lntPrint(dbOut, lnt1); |
| 1394 | fnewline(dbOut); |
| 1395 | fprintf(dbOut,"Second tree "); |
| 1396 | lntPrint(dbOut, lnt2); |
| 1397 | fnewline(dbOut); |
| 1398 | |
| 1399 | if (tok1){ fprintf(dbOut," with tok1 "); tokPrint(dbOut,tok1); } |
| 1400 | else {fprintf(dbOut,"No first token\n"); } |
| 1401 | if (tok2){ fprintf(dbOut," with tok2 "); tokPrint(dbOut,tok2); } |
| 1402 | else {fprintf(dbOut,"No second token\n"); } |
| 1403 | fnewline(dbOut); |
| 1404 | } |
| 1405 | |
| 1406 | /* Rule 1 */ |
| 1407 | if (linIsCom(lnt1)(!((lnt1)->has & (1<<0))) || linIsBlank(lnt1)(!((lnt1)->has & (1<<1))) || linIsBlank(lnt2)(!((lnt2)->has & (1<<1)))) |
| 1408 | return false((int) 0); |
| 1409 | |
| 1410 | if (!tok1 || !tok2) |
| 1411 | return true1; |
| 1412 | |
| 1413 | /* Rule 2 */ |
| 1414 | if (tokIs(tok1, KW_Comma)((tok1)->tag == (KW_Comma)) || tokIsOpener(tok1)((tokInfoTable[((tok1)->tag)-TK_START]).isOpener)) |
| 1415 | return false((int) 0); |
| 1416 | |
| 1417 | /* Rule 3 */ |
| 1418 | if (tokIsFollower(tok2)((tokInfoTable[((tok2)->tag)-TK_START]).isFollower) || tokIsCloser(tok2)((tokInfoTable[((tok2)->tag)-TK_START]).isCloser)) |
| 1419 | return false((int) 0); |
| 1420 | |
| 1421 | return true1; |
| 1422 | } |
| 1423 |