|
|
1.1 ! root 1: /* GNU Emacs routines to deal with syntax tables; also word and list parsing. ! 2: Copyright (C) 1985 Richard M. Stallman. ! 3: ! 4: This file is part of GNU Emacs. ! 5: ! 6: GNU Emacs is distributed in the hope that it will be useful, ! 7: but WITHOUT ANY WARRANTY. No author or distributor ! 8: accepts responsibility to anyone for the consequences of using it ! 9: or for whether it serves any particular purpose or works at all, ! 10: unless he says so in writing. Refer to the GNU Emacs General Public ! 11: License for full details. ! 12: ! 13: Everyone is granted permission to copy, modify and redistribute ! 14: GNU Emacs, but only under the conditions described in the ! 15: GNU Emacs General Public License. A copy of this license is ! 16: supposed to have been given to you along with GNU Emacs so you ! 17: can know your rights and responsibilities. It should be in a ! 18: file named COPYING. Among other things, the copyright notice ! 19: and this notice must be preserved on all copies. */ ! 20: ! 21: ! 22: #include "config.h" ! 23: #include <ctype.h> ! 24: #include "lisp.h" ! 25: #include "commands.h" ! 26: #include "buffer.h" ! 27: #include "syntax.h" ! 28: ! 29: Lisp_Object Qsyntax_table_p, Vstandard_syntax_table; ! 30: ! 31: /* There is an alist of syntax tables: names (strings) vs obarrays. */ ! 32: ! 33: DEFUN ("syntax-table-p", Fsyntax_table_p, Ssyntax_table_p, 1, 1, 0, ! 34: "Return t if ARG is a syntax table.\n\ ! 35: Any vector of 256 elements will do.") ! 36: (obj) ! 37: Lisp_Object obj; ! 38: { ! 39: if (XTYPE (obj) == Lisp_Vector && XVECTOR (obj)->size == 0400) ! 40: return Qt; ! 41: return Qnil; ! 42: } ! 43: ! 44: Lisp_Object ! 45: check_syntax_table (obj) ! 46: Lisp_Object obj; ! 47: { ! 48: register Lisp_Object tem; ! 49: while (tem = Fsyntax_table_p (obj), ! 50: NULL (tem)) ! 51: obj = wrong_type_argument (Qsyntax_table_p, obj, 0); ! 52: return obj; ! 53: } ! 54: ! 55: ! 56: DEFUN ("syntax-table", Fsyntax_table, Ssyntax_table, 0, 0, 0, ! 57: "Return the current syntax table.\n\ ! 58: This is the one specified by the current buffer.") ! 59: () ! 60: { ! 61: Lisp_Object vector; ! 62: XSET (vector, Lisp_Vector, bf_cur->syntax_table_v); ! 63: return vector; ! 64: } ! 65: ! 66: DEFUN ("standard-syntax-table", Fstandard_syntax_table, ! 67: Sstandard_syntax_table, 0, 0, 0, ! 68: "Return the standard syntax table.\n\ ! 69: This is the one used for new buffers.") ! 70: () ! 71: { ! 72: return Vstandard_syntax_table; ! 73: } ! 74: ! 75: DEFUN ("copy-syntax-table", Fcopy_syntax_table, Scopy_syntax_table, 0, 1, 0, ! 76: "Construct a new syntax table and return it.\n\ ! 77: It is a copy of the TABLE, which defaults to the standard syntax table.") ! 78: (table) ! 79: Lisp_Object table; ! 80: { ! 81: Lisp_Object size, val; ! 82: XFASTINT (size) = 0400; ! 83: XFASTINT (val) = 0; ! 84: val = Fmake_vector (size, val); ! 85: if (!NULL (table)) ! 86: table = check_syntax_table (table); ! 87: else if (NULL (Vstandard_syntax_table)) ! 88: /* Can only be null during initialization */ ! 89: return val; ! 90: else table = Vstandard_syntax_table; ! 91: ! 92: bcopy (XVECTOR (table)->contents, ! 93: XVECTOR (val)->contents, 0400 * sizeof (Lisp_Object)); ! 94: return val; ! 95: } ! 96: ! 97: DEFUN ("set-syntax-table", Fset_syntax_table, Sset_syntax_table, 1, 1, 0, ! 98: "Select a new syntax table for the current buffer.\n\ ! 99: One argument, a syntax table.") ! 100: (table) ! 101: Lisp_Object table; ! 102: { ! 103: table = check_syntax_table (table); ! 104: bf_cur->syntax_table_v = XVECTOR (table); ! 105: return table; ! 106: } ! 107: ! 108: /* Convert a letter which signifies a syntax code ! 109: into the code it signifies. ! 110: This is used by modify-syntax-entry, and other things. */ ! 111: ! 112: char syntax_spec_code[0400] = ! 113: { 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, ! 114: 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, ! 115: 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, ! 116: 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, ! 117: (char) Swhitespace, 0377, (char) Sstring, 0377, ! 118: (char) Smath, 0377, 0377, (char) Squote, ! 119: (char) Sopen, (char) Sclose, 0377, 0377, ! 120: 0377, (char) Swhitespace, (char) Spunct, (char) Scharquote, ! 121: 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, ! 122: 0377, 0377, 0377, 0377, ! 123: (char) Scomment, 0377, (char) Sendcomment, 0377, ! 124: 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, /* @, A, ... */ ! 125: 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, ! 126: 0377, 0377, 0377, 0377, 0377, 0377, 0377, (char) Sword, ! 127: 0377, 0377, 0377, 0377, (char) Sescape, 0377, 0377, (char) Ssymbol, ! 128: 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, /* `, a, ... */ ! 129: 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, ! 130: 0377, 0377, 0377, 0377, 0377, 0377, 0377, (char) Sword, ! 131: 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377 ! 132: }; ! 133: ! 134: /* Indexed by syntax code, give the letter that describes it. */ ! 135: ! 136: char syntax_code_spec[13] = ! 137: { ! 138: ' ', '.', 'w', '_', '(', ')', '\'', '\"', '$', '\\', '/', '<', '>' ! 139: }; ! 140: ! 141: DEFUN ("char-syntax", Fchar_syntax, Schar_syntax, 1, 1, 0, ! 142: "Return the syntax code of CHAR, described by a character.\n\ ! 143: For example, if CHAR is a word constituent, ?w is returned.\n\ ! 144: The characters that correspond to various syntax codes\n\ ! 145: are listed in the documentation of modify-syntax-entry.") ! 146: (ch) ! 147: Lisp_Object ch; ! 148: { ! 149: CHECK_NUMBER (ch, 0); ! 150: return make_number (syntax_code_spec[(int) SYNTAX (XINT (ch))]); ! 151: } ! 152: ! 153: DEFUN ("modify-syntax-entry", Fmodify_syntax_entry, Smodify_syntax_entry, 2, 3, ! 154: /* I really don't know why this is interactive ! 155: help-form should at least be made useful whilst reading the second arg ! 156: */ ! 157: "cSet syntax for character: \nsSet syntax for %s to: ", ! 158: 0 /* See auxdoc.c */) ! 159: (c, newentry, syntax_table) ! 160: Lisp_Object c, newentry, syntax_table; ! 161: { ! 162: register unsigned char *p, match; ! 163: register enum syntaxcode code; ! 164: Lisp_Object val; ! 165: ! 166: CHECK_NUMBER (c, 0); ! 167: CHECK_STRING (newentry, 1); ! 168: if (NULL (syntax_table)) ! 169: XSET (syntax_table, Lisp_Vector, bf_cur->syntax_table_v); ! 170: else syntax_table = check_syntax_table (syntax_table); ! 171: ! 172: p = XSTRING (newentry)->data; ! 173: code = (enum syntaxcode) syntax_spec_code[*p++]; ! 174: if (((int) code & 0377) == 0377) ! 175: error ("invalid syntax description letter: %c", c); ! 176: ! 177: match = *p; ! 178: if (match) p++; ! 179: if (match == ' ') match = 0; ! 180: ! 181: XFASTINT (val) = (match << 8) + (int) code; ! 182: while (*p) ! 183: switch (*p++) ! 184: { ! 185: case '1': ! 186: XFASTINT (val) |= 1 << 16; ! 187: break; ! 188: ! 189: case '2': ! 190: XFASTINT (val) |= 1 << 17; ! 191: break; ! 192: ! 193: case '3': ! 194: XFASTINT (val) |= 1 << 18; ! 195: break; ! 196: ! 197: case '4': ! 198: XFASTINT (val) |= 1 << 19; ! 199: break; ! 200: } ! 201: ! 202: XVECTOR (syntax_table)->contents[XINT (c)] = val; ! 203: ! 204: return Qnil; ! 205: } ! 206: ! 207: /* Dump syntax table to buffer in human-readable format */ ! 208: ! 209: describe_syntax (value) ! 210: Lisp_Object value; ! 211: { ! 212: register enum syntaxcode code; ! 213: char desc, match, start1, start2, end1, end2; ! 214: char str[2]; ! 215: ! 216: if (XTYPE (value) != Lisp_Int) ! 217: { ! 218: InsStr ("invalid"); ! 219: return; ! 220: } ! 221: ! 222: code = (enum syntaxcode) (XINT (value) & 0377); ! 223: match = (XINT (value) >> 8) & 0377; ! 224: start1 = (XINT (value) >> 16) & 1; ! 225: start2 = (XINT (value) >> 17) & 1; ! 226: end1 = (XINT (value) >> 18) & 1; ! 227: end2 = (XINT (value) >> 19) & 1; ! 228: ! 229: if ((int) code < 0 || (int) code >= (int) Smax) ! 230: { ! 231: InsStr ("invalid"); ! 232: return; ! 233: } ! 234: desc = syntax_code_spec[(int) code]; ! 235: ! 236: str[0] = desc, str[1] = 0; ! 237: InsCStr (str, 1); ! 238: ! 239: str[0] = match ? match : ' '; ! 240: InsCStr (str, 1); ! 241: ! 242: ! 243: if (start1) ! 244: InsCStr ("1", 1); ! 245: if (start2) ! 246: InsCStr ("2", 1); ! 247: ! 248: if (end1) ! 249: InsCStr ("3", 1); ! 250: if (end2) ! 251: InsCStr ("4", 1); ! 252: ! 253: InsStr ("\twhich means: "); ! 254: ! 255: #ifdef SWITCH_ENUM_BUG ! 256: switch ((int) code) ! 257: #else ! 258: switch (code) ! 259: #endif ! 260: { ! 261: case Swhitespace: ! 262: InsStr ("whitespace"); break; ! 263: case Spunct: ! 264: InsStr ("punctuation"); break; ! 265: case Sword: ! 266: InsStr ("word"); break; ! 267: case Ssymbol: ! 268: InsStr ("symbol"); break; ! 269: case Sopen: ! 270: InsStr ("open"); break; ! 271: case Sclose: ! 272: InsStr ("close"); break; ! 273: case Squote: ! 274: InsStr ("quote"); break; ! 275: case Sstring: ! 276: InsStr ("string"); break; ! 277: case Smath: ! 278: InsStr ("math"); break; ! 279: case Sescape: ! 280: InsStr ("escape"); break; ! 281: case Scharquote: ! 282: InsStr ("charquote"); break; ! 283: case Scomment: ! 284: InsStr ("comment"); break; ! 285: case Sendcomment: ! 286: InsStr ("endcomment"); break; ! 287: default: ! 288: InsStr ("invalid"); ! 289: return; ! 290: } ! 291: ! 292: if (match) ! 293: { ! 294: InsStr (", matches "); ! 295: ! 296: str[0] = match, str[1] = 0; ! 297: InsCStr (str, 1); ! 298: } ! 299: ! 300: if (start1) ! 301: InsStr (",\n\t is the first character of a comment-start sequence"); ! 302: if (start2) ! 303: InsStr (",\n\t is the second character of a comment-start sequence"); ! 304: ! 305: if (end1) ! 306: InsStr (",\n\t is the first character of a comment-end sequence"); ! 307: if (end2) ! 308: InsStr (",\n\t is the second character of a comment-end sequence"); ! 309: } ! 310: ! 311: Lisp_Object ! 312: describe_syntax_1 (vector) ! 313: Lisp_Object vector; ! 314: { ! 315: struct buffer *old = bf_cur; ! 316: SetBfp (XBUFFER (Vstandard_output)); ! 317: describe_vector (vector, Qnil, describe_syntax, 0); ! 318: SetBfp (old); ! 319: return Qnil; ! 320: } ! 321: ! 322: DEFUN ("describe-syntax", Fdescribe_syntax, Sdescribe_syntax, 0, 0, "", ! 323: "Describe the syntax specifications in the syntax table.\n\ ! 324: The descriptions are inserted in a buffer, which is selected so you can see it.") ! 325: () ! 326: { ! 327: register Lisp_Object vector; ! 328: ! 329: XSET (vector, Lisp_Vector, bf_cur->syntax_table_v); ! 330: internal_with_output_to_temp_buffer ! 331: ("*Help*", describe_syntax_1, vector); ! 332: ! 333: return Qnil; ! 334: } ! 335: ! 336: /* Return the position across `count' words from `from'. ! 337: If that many words cannot be found before the end of the buffer, return 0. ! 338: `count' negative means scan backward and stop at word beginning. */ ! 339: ! 340: scan_words (from, count) ! 341: register int from, count; ! 342: { ! 343: register int beg = FirstCharacter; ! 344: register int end = NumCharacters + 1; ! 345: ! 346: immediate_quit = 1; ! 347: QUIT; ! 348: ! 349: while (count > 0) ! 350: { ! 351: while (1) ! 352: { ! 353: if (from == end) ! 354: { ! 355: immediate_quit = 0; ! 356: return 0; ! 357: } ! 358: if (SYNTAX(CharAt (from)) == Sword) ! 359: break; ! 360: from++; ! 361: } ! 362: while (1) ! 363: { ! 364: if (from == end) break; ! 365: if (SYNTAX(CharAt (from)) != Sword) ! 366: break; ! 367: from++; ! 368: } ! 369: count--; ! 370: } ! 371: while (count < 0) ! 372: { ! 373: while (1) ! 374: { ! 375: if (from == beg) ! 376: { ! 377: immediate_quit = 0; ! 378: return 0; ! 379: } ! 380: if (SYNTAX(CharAt (from - 1)) == Sword) ! 381: break; ! 382: from--; ! 383: } ! 384: while (1) ! 385: { ! 386: if (from == beg) break; ! 387: if (SYNTAX(CharAt (from - 1)) != Sword) ! 388: break; ! 389: from--; ! 390: } ! 391: count++; ! 392: } ! 393: ! 394: immediate_quit = 0; ! 395: ! 396: return from; ! 397: } ! 398: ! 399: DEFUN ("forward-word", Fforward_word, Sforward_word, 1, 1, "p", ! 400: "Move point forward ARG words (backward if ARG is negative).\n\ ! 401: Normally returns t.\n\ ! 402: If an edge of the buffer is reached, point is left there\n\ ! 403: and nil is returned.") ! 404: (count) ! 405: Lisp_Object count; ! 406: { ! 407: int val; ! 408: CHECK_NUMBER (count, 0); ! 409: ! 410: if (!(val = scan_words (point, XINT (count)))) ! 411: { ! 412: SetPoint (XINT (count) > 0 ? NumCharacters + 1 : FirstCharacter); ! 413: return Qnil; ! 414: } ! 415: SetPoint (val); ! 416: return Qt; ! 417: } ! 418: ! 419: int parse_sexp_ignore_comments; ! 420: ! 421: Lisp_Object ! 422: scan_lists (from, count, depth, sexpflag) ! 423: register int from; ! 424: int count, depth, sexpflag; ! 425: { ! 426: Lisp_Object val; ! 427: register int stop; ! 428: register int c; ! 429: char stringterm; ! 430: int quoted; ! 431: int mathexit = 0; ! 432: register enum syntaxcode code; ! 433: int min_depth = depth; /* Err out if depth gets less than this. */ ! 434: ! 435: if (depth > 0) min_depth = 0; ! 436: ! 437: immediate_quit = 1; ! 438: QUIT; ! 439: ! 440: while (count > 0) ! 441: { ! 442: stop = NumCharacters + 1; ! 443: while (from < stop) ! 444: { ! 445: c = CharAt (from); ! 446: code = SYNTAX(c); ! 447: from++; ! 448: if (from < stop && SYNTAX_COMSTART_FIRST (c) ! 449: && SYNTAX_COMSTART_SECOND (CharAt (from)) ! 450: && parse_sexp_ignore_comments) ! 451: code = Scomment, from++; ! 452: ! 453: #ifdef SWITCH_ENUM_BUG ! 454: switch ((int) code) ! 455: #else ! 456: switch (code) ! 457: #endif ! 458: { ! 459: case Sescape: ! 460: case Scharquote: ! 461: if (from == stop) goto lose; ! 462: from++; ! 463: /* treat following character as a word constituent */ ! 464: case Sword: ! 465: case Ssymbol: ! 466: if (depth || !sexpflag) break; ! 467: /* This word counts as a sexp; return at end of it. */ ! 468: while (from < stop) ! 469: { ! 470: #ifdef SWITCH_ENUM_BUG ! 471: switch ((int) SYNTAX(CharAt (from))) ! 472: #else ! 473: switch (SYNTAX(CharAt (from))) ! 474: #endif ! 475: { ! 476: case Scharquote: ! 477: case Sescape: ! 478: from++; ! 479: if (from == stop) goto lose; ! 480: break; ! 481: case Sword: ! 482: case Ssymbol: ! 483: break; ! 484: default: ! 485: goto done; ! 486: } ! 487: from++; ! 488: } ! 489: goto done; ! 490: ! 491: case Scomment: ! 492: if (!parse_sexp_ignore_comments) break; ! 493: while (1) ! 494: { ! 495: if (from == stop) goto done; ! 496: if (SYNTAX (c = CharAt (from)) == Sendcomment) ! 497: break; ! 498: from++; ! 499: if (from < stop && SYNTAX_COMEND_FIRST (c) ! 500: && SYNTAX_COMEND_SECOND (CharAt (from))) ! 501: { from++; break; } ! 502: } ! 503: break; ! 504: ! 505: case Smath: ! 506: if (!sexpflag) ! 507: break; ! 508: if (from != stop && c == CharAt (from)) ! 509: from++; ! 510: if (mathexit) goto close1; ! 511: mathexit = 1; ! 512: ! 513: case Sopen: ! 514: if (!++depth) goto done; ! 515: break; ! 516: ! 517: case Sclose: ! 518: close1: ! 519: if (!--depth) goto done; ! 520: if (depth < min_depth) ! 521: error ("Containing expression ends prematurely"); ! 522: break; ! 523: ! 524: case Sstring: ! 525: stringterm = CharAt (from - 1); ! 526: while (1) ! 527: { ! 528: if (from >= stop) goto lose; ! 529: if (CharAt (from) == stringterm) break; ! 530: #ifdef SWITCH_ENUM_BUG ! 531: switch ((int) SYNTAX(CharAt (from))) ! 532: #else ! 533: switch (SYNTAX(CharAt (from))) ! 534: #endif ! 535: { ! 536: case Scharquote: ! 537: case Sescape: ! 538: from++; ! 539: } ! 540: from++; ! 541: } ! 542: from++; ! 543: if (!depth && sexpflag) goto done; ! 544: break; ! 545: } ! 546: } ! 547: ! 548: /* Reached end of buffer. Error if within object, return nil if between */ ! 549: if (depth) goto lose; ! 550: ! 551: immediate_quit = 0; ! 552: return Qnil; ! 553: ! 554: /* End of object reached */ ! 555: done: ! 556: count--; ! 557: } ! 558: ! 559: while (count < 0) ! 560: { ! 561: stop = FirstCharacter; ! 562: while (from > stop) ! 563: { ! 564: from--; ! 565: if (quoted = char_quoted (from)) ! 566: from--; ! 567: c = CharAt (from); ! 568: code = SYNTAX (c); ! 569: if (from > stop && SYNTAX_COMEND_SECOND (c) ! 570: && SYNTAX_COMEND_FIRST (CharAt (from - 1)) ! 571: && !char_quoted (from - 1) ! 572: && parse_sexp_ignore_comments) ! 573: code = Sendcomment, from--; ! 574: ! 575: #ifdef SWITCH_ENUM_BUG ! 576: switch ((int) (quoted ? Sword : code)) ! 577: #else ! 578: switch (quoted ? Sword : code) ! 579: #endif ! 580: { ! 581: case Sword: ! 582: case Ssymbol: ! 583: if (depth || !sexpflag) break; ! 584: /* This word counts as a sexp; count object finished after passing it. */ ! 585: while (from > stop) ! 586: { ! 587: if (quoted = char_quoted (from - 1)) ! 588: from--; ! 589: if (! (quoted || SYNTAX(CharAt (from - 1)) == Sword || ! 590: SYNTAX(CharAt (from - 1)) == Ssymbol)) ! 591: goto done2; ! 592: from--; ! 593: } ! 594: goto done2; ! 595: ! 596: case Smath: ! 597: if (!sexpflag) ! 598: break; ! 599: if (from != stop && c == CharAt (from - 1)) ! 600: from--; ! 601: if (mathexit) goto open2; ! 602: mathexit = 1; ! 603: ! 604: case Sclose: ! 605: if (!++depth) goto done2; ! 606: break; ! 607: ! 608: case Sopen: ! 609: open2: ! 610: if (!--depth) goto done2; ! 611: if (depth < min_depth) ! 612: error ("Containing expression ends prematurely"); ! 613: break; ! 614: ! 615: case Sendcomment: ! 616: if (!parse_sexp_ignore_comments) break; ! 617: if (from != stop) from--; ! 618: while (1) ! 619: { ! 620: if (SYNTAX (c = CharAt (from)) == Scomment) ! 621: break; ! 622: if (from == stop) goto done; ! 623: from--; ! 624: if (SYNTAX_COMSTART_SECOND (c) ! 625: && SYNTAX_COMSTART_FIRST (CharAt (from)) ! 626: && !char_quoted (from)) ! 627: break; ! 628: } ! 629: break; ! 630: ! 631: case Sstring: ! 632: stringterm = CharAt (from); ! 633: while (1) ! 634: { ! 635: if (from == stop) goto lose; ! 636: if (!char_quoted (from - 1) ! 637: && stringterm == CharAt (from - 1)) ! 638: break; ! 639: from--; ! 640: } ! 641: from--; ! 642: if (!depth && sexpflag) goto done2; ! 643: break; ! 644: } ! 645: } ! 646: ! 647: /* Reached start of buffer. Error if within object, return nil if between */ ! 648: if (depth) goto lose; ! 649: ! 650: immediate_quit = 0; ! 651: return Qnil; ! 652: ! 653: done2: ! 654: count++; ! 655: } ! 656: ! 657: ! 658: immediate_quit = 0; ! 659: XFASTINT (val) = from; ! 660: return val; ! 661: ! 662: lose: ! 663: error ("Unbalanced parentheses"); ! 664: /* NOTREACHED */ ! 665: } ! 666: ! 667: char_quoted (pos) ! 668: register int pos; ! 669: { ! 670: register enum syntaxcode code; ! 671: register int beg = FirstCharacter; ! 672: register int quoted = 0; ! 673: ! 674: while (pos > beg && ! 675: ((code = SYNTAX (CharAt (pos - 1))) == Scharquote ! 676: || code == Sescape)) ! 677: pos--, quoted = !quoted; ! 678: return quoted; ! 679: } ! 680: ! 681: DEFUN ("scan-lists", Fscan_lists, Sscan_lists, 3, 3, 0, ! 682: "Scan from character number FROM by COUNT lists.\n\ ! 683: Returns the character number of the position thus found.\n\ ! 684: \n\ ! 685: If DEPTH is nonzero, paren depth begins counting from that value,\n\ ! 686: only places where the depth in parentheses becomes zero\n\ ! 687: are candidates for stopping; COUNT such places are counted.\n\ ! 688: Thus, a positive value for DEPTH means go out levels.\n\ ! 689: \n\ ! 690: Comments are ignored if parse-sexp-ignore-comments is non-nil.\n\ ! 691: \n\ ! 692: If the beginning or end of (the visible part of) the buffer is reached\n\ ! 693: and the depth is wrong, an error is signaled.\n\ ! 694: If the depth is right but the count is not used up, nil is returned.") ! 695: (from, count, depth) ! 696: Lisp_Object from, count, depth; ! 697: { ! 698: CHECK_NUMBER (from, 0); ! 699: CHECK_NUMBER (count, 1); ! 700: CHECK_NUMBER (depth, 2); ! 701: ! 702: return scan_lists (XINT (from), XINT (count), XINT (depth), 0); ! 703: } ! 704: ! 705: DEFUN ("scan-sexps", Fscan_sexps, Sscan_sexps, 2, 2, 0, ! 706: "Scan from character number FROM by COUNT balanced expressions.\n\ ! 707: Returns the character number of the position thus found.\n\ ! 708: \n\ ! 709: Comments are ignored if parse-sexp-ignore-comments is non-nil.\n\ ! 710: \n\ ! 711: If the beginning or end of (the visible part of) the buffer is reached\n\ ! 712: in the middle of a parenthetical grouping, an error is signaled.\n\ ! 713: If the beginning or end is reached between groupings but before count is used up,\n\ ! 714: nil is returned.") ! 715: (from, count) ! 716: Lisp_Object from, count; ! 717: { ! 718: CHECK_NUMBER (from, 0); ! 719: CHECK_NUMBER (count, 1); ! 720: ! 721: return scan_lists (XINT (from), XINT (count), 0, 1); ! 722: } ! 723: ! 724: DEFUN ("backward-prefix-chars", Fbackward_prefix_chars, Sbackward_prefix_chars, ! 725: 0, 0, 0, ! 726: "Move point backward over any number of chars with syntax \"prefix\".") ! 727: () ! 728: { ! 729: int beg = FirstCharacter; ! 730: int pos = point; ! 731: ! 732: while (pos > beg && !char_quoted (pos - 1) && SYNTAX (CharAt (pos - 1)) == Squote) ! 733: pos--; ! 734: ! 735: SetPoint (pos); ! 736: ! 737: return Qnil; ! 738: } ! 739: ! 740: struct lisp_parse_state ! 741: { ! 742: int depth; /* Depth at end of parsing */ ! 743: int instring; /* -1 if not within string, else desired terminator. */ ! 744: int incomment; /* Nonzero if within a comment at end of parsing */ ! 745: int quoted; /* Nonzero if just after an escape char at end of parsing */ ! 746: int thislevelstart; /* Char number of most recent start-of-expression at current level */ ! 747: int prevlevelstart; /* Char number of start of containing expression */ ! 748: int location; /* Char number at which parsing stopped. */ ! 749: }; ! 750: ! 751: /* Parse forward from `from' to `end', assuming that `from' ! 752: is the start of a function, and return a description of the state of the parse at `end'. */ ! 753: ! 754: struct lisp_parse_state val_scan_sexps_forward; ! 755: ! 756: struct lisp_parse_state * ! 757: scan_sexps_forward (from, end, targetdepth, stopbefore, oldstate) ! 758: register int from; ! 759: int end, targetdepth, stopbefore; ! 760: Lisp_Object oldstate; ! 761: { ! 762: struct lisp_parse_state state; ! 763: ! 764: register enum syntaxcode code; ! 765: struct level { int last, prev; }; ! 766: struct level levelstart[100]; ! 767: register struct level *curlevel = levelstart; ! 768: struct level *endlevel = levelstart + 100; ! 769: char prev; ! 770: register int depth; /* Paren depth of current scanning location. ! 771: level - levelstart equals this except ! 772: when the depth becomes negative. */ ! 773: int start_quoted = 0; /* Nonzero means starting after a char quote */ ! 774: Lisp_Object tem; ! 775: ! 776: immediate_quit = 1; ! 777: QUIT; ! 778: ! 779: if (NULL (oldstate)) ! 780: { ! 781: depth = 0; ! 782: state.instring = -1; ! 783: state.incomment = 0; ! 784: } ! 785: else ! 786: { ! 787: tem = Fcar (oldstate); ! 788: if (!NULL (tem)) ! 789: depth = XINT (tem); ! 790: else ! 791: depth = 0; ! 792: ! 793: oldstate = Fcdr (oldstate); ! 794: oldstate = Fcdr (oldstate); ! 795: oldstate = Fcdr (oldstate); ! 796: tem = Fcar (oldstate); ! 797: state.instring = !NULL (tem) ? XINT (tem) : -1; ! 798: ! 799: oldstate = Fcdr (oldstate); ! 800: tem = Fcar (oldstate); ! 801: state.incomment = !NULL (tem); ! 802: ! 803: oldstate = Fcdr (oldstate); ! 804: tem = Fcar (oldstate); ! 805: start_quoted = !NULL (tem); ! 806: } ! 807: state.quoted = 0; ! 808: ! 809: curlevel->prev = -1; ! 810: ! 811: /* Enter the loop at a place appropriate for initial state. */ ! 812: ! 813: if (state.incomment) goto startincomment; ! 814: if (state.instring >= 0) ! 815: { ! 816: if (start_quoted) goto startquotedinstring; ! 817: goto startinstring; ! 818: } ! 819: if (start_quoted) goto startquoted; ! 820: ! 821: while (from < end) ! 822: { ! 823: code = SYNTAX(CharAt (from)); ! 824: from++; ! 825: if (from < end && SYNTAX_COMSTART_FIRST (CharAt (from - 1)) ! 826: && SYNTAX_COMSTART_SECOND (CharAt (from))) ! 827: code = Scomment, from++; ! 828: #ifdef SWITCH_ENUM_BUG ! 829: switch ((int) code) ! 830: #else ! 831: switch (code) ! 832: #endif ! 833: { ! 834: case Sescape: ! 835: case Scharquote: ! 836: if (stopbefore) goto stop; /* this arg means stop at sexp start */ ! 837: curlevel->last = from - 1; ! 838: startquoted: ! 839: if (from == end) goto endquoted; ! 840: from++; ! 841: goto symstarted; ! 842: /* treat following character as a word constituent */ ! 843: case Sword: ! 844: case Ssymbol: ! 845: if (stopbefore) goto stop; /* this arg means stop at sexp start */ ! 846: curlevel->last = from - 1; ! 847: symstarted: ! 848: while (from < end) ! 849: { ! 850: #ifdef SWITCH_ENUM_BUG ! 851: switch ((int) SYNTAX(CharAt (from))) ! 852: #else ! 853: switch (SYNTAX(CharAt (from))) ! 854: #endif ! 855: { ! 856: case Scharquote: ! 857: case Sescape: ! 858: from++; ! 859: if (from == end) goto endquoted; ! 860: break; ! 861: case Sword: ! 862: case Ssymbol: ! 863: break; ! 864: default: ! 865: goto symdone; ! 866: } ! 867: from++; ! 868: } ! 869: symdone: ! 870: curlevel->prev = curlevel->last; ! 871: break; ! 872: ! 873: case Scomment: ! 874: state.incomment = 1; ! 875: startincomment: ! 876: while (1) ! 877: { ! 878: if (from == end) goto done; ! 879: if (SYNTAX (prev = CharAt (from)) == Sendcomment) ! 880: break; ! 881: from++; ! 882: if (from < end && SYNTAX_COMEND_FIRST (prev) ! 883: && SYNTAX_COMEND_SECOND (CharAt (from))) ! 884: { from++; break; } ! 885: } ! 886: state.incomment = 0; ! 887: break; ! 888: ! 889: case Sopen: ! 890: if (stopbefore) goto stop; /* this arg means stop at sexp start */ ! 891: depth++; ! 892: /* curlevel++->last ran into compiler bug on Apollo */ ! 893: curlevel->last = from - 1; ! 894: if (++curlevel == endlevel) ! 895: error ("Nesting too deep for parser"); ! 896: curlevel->prev = -1; ! 897: curlevel->last = -1; ! 898: if (!--targetdepth) goto done; ! 899: break; ! 900: ! 901: case Sclose: ! 902: depth--; ! 903: if (curlevel != levelstart) ! 904: curlevel--; ! 905: curlevel->prev = curlevel->last; ! 906: if (!++targetdepth) goto done; ! 907: break; ! 908: ! 909: case Sstring: ! 910: if (stopbefore) goto stop; /* this arg means stop at sexp start */ ! 911: curlevel->last = from - 1; ! 912: state.instring = CharAt (from - 1); ! 913: startinstring: ! 914: while (1) ! 915: { ! 916: if (from >= end) goto done; ! 917: if (CharAt (from) == state.instring) break; ! 918: #ifdef SWITCH_ENUM_BUG ! 919: switch ((int) SYNTAX(CharAt (from))) ! 920: #else ! 921: switch (SYNTAX(CharAt (from))) ! 922: #endif ! 923: { ! 924: case Scharquote: ! 925: case Sescape: ! 926: from++; ! 927: startquotedinstring: ! 928: if (from >= end) goto endquoted; ! 929: } ! 930: from++; ! 931: } ! 932: state.instring = -1; ! 933: curlevel->prev = curlevel->last; ! 934: from++; ! 935: break; ! 936: ! 937: case Smath: ! 938: break; ! 939: } ! 940: } ! 941: goto done; ! 942: ! 943: stop: /* Here if stopping before start of sexp. */ ! 944: from--; /* We have just fetched the char that starts it; */ ! 945: goto done; /* but return the position before it. */ ! 946: ! 947: endquoted: ! 948: state.quoted = 1; ! 949: done: ! 950: state.depth = depth; ! 951: state.thislevelstart = curlevel->prev; ! 952: state.prevlevelstart ! 953: = (curlevel == levelstart) ? -1 : (curlevel - 1)->last; ! 954: state.location = from; ! 955: immediate_quit = 0; ! 956: ! 957: val_scan_sexps_forward = state; ! 958: return &val_scan_sexps_forward; ! 959: } ! 960: ! 961: DEFUN ("parse-partial-sexp", Fparse_partial_sexp, Sparse_partial_sexp, 2, 5, 0, ! 962: 0 /* See auxdoc.c */) ! 963: (from, to, targetdepth, stopbefore, oldstate) ! 964: Lisp_Object from, to, targetdepth, stopbefore, oldstate; ! 965: { ! 966: struct lisp_parse_state state; ! 967: int target; ! 968: ! 969: if (!NULL (targetdepth)) ! 970: { ! 971: CHECK_NUMBER (targetdepth, 3); ! 972: target = XINT (targetdepth); ! 973: } ! 974: else ! 975: target = -100000; /* We won't reach this depth */ ! 976: ! 977: validate_region (&from, &to); ! 978: state = *scan_sexps_forward (XINT (from), XINT (to), ! 979: target, !NULL (stopbefore), oldstate); ! 980: ! 981: SetPoint (state.location); ! 982: ! 983: return Fcons (make_number (state.depth), ! 984: Fcons (state.prevlevelstart < 0 ? Qnil : make_number (state.prevlevelstart), ! 985: Fcons (state.thislevelstart < 0 ? Qnil : make_number (state.thislevelstart), ! 986: Fcons (state.instring >= 0 ? make_number (state.instring) : Qnil, ! 987: Fcons (state.incomment ? Qt : Qnil, ! 988: Fcons (state.quoted ? Qt : Qnil, Qnil)))))); ! 989: } ! 990: ! 991: init_syntax_once () ! 992: { ! 993: register int i; ! 994: register struct Lisp_Vector *v; ! 995: ! 996: /* Set this now, so first buffer creation can refer to it. */ ! 997: /* Make it nil before calling copy-syntax-table ! 998: so that copy-syntax-table will know not to try to copy from garbage */ ! 999: Vstandard_syntax_table = Qnil; ! 1000: Vstandard_syntax_table = Fcopy_syntax_table (Qnil); ! 1001: ! 1002: v = XVECTOR (Vstandard_syntax_table); ! 1003: ! 1004: for (i = 'a'; i <= 'z'; i++) ! 1005: XFASTINT (v->contents[i]) = (int) Sword; ! 1006: for (i = 'A'; i <= 'Z'; i++) ! 1007: XFASTINT (v->contents[i]) = (int) Sword; ! 1008: for (i = '0'; i <= '9'; i++) ! 1009: XFASTINT (v->contents[i]) = (int) Sword; ! 1010: XFASTINT (v->contents['$']) = (int) Sword; ! 1011: XFASTINT (v->contents['%']) = (int) Sword; ! 1012: ! 1013: XFASTINT (v->contents['(']) = (int) Sopen + (')' << 8); ! 1014: XFASTINT (v->contents[')']) = (int) Sclose + ('(' << 8); ! 1015: XFASTINT (v->contents['[']) = (int) Sopen + (']' << 8); ! 1016: XFASTINT (v->contents[']']) = (int) Sclose + ('[' << 8); ! 1017: XFASTINT (v->contents['{']) = (int) Sopen + ('}' << 8); ! 1018: XFASTINT (v->contents['}']) = (int) Sclose + ('{' << 8); ! 1019: XFASTINT (v->contents['"']) = (int) Sstring; ! 1020: XFASTINT (v->contents['\\']) = (int) Sescape; ! 1021: ! 1022: for (i = 0; i < 10; i++) ! 1023: XFASTINT (v->contents["_-+*/&|<>="[i]]) = (int) Ssymbol; ! 1024: ! 1025: for (i = 0; i < 12; i++) ! 1026: XFASTINT (v->contents[".,;:?!#@~^'`"[i]]) = (int) Spunct; ! 1027: } ! 1028: ! 1029: syms_of_syntax () ! 1030: { ! 1031: Qsyntax_table_p = intern ("syntax-table-p"); ! 1032: staticpro (&Qsyntax_table_p); ! 1033: ! 1034: /* Mustn't let user clobber this! ! 1035: DefLispVar ("standard-syntax-table", &Vstandard_syntax_table, ! 1036: "The syntax table used by buffers that don't specify another."); ! 1037: */ ! 1038: staticpro (&Vstandard_syntax_table); ! 1039: ! 1040: DefBoolVar ("parse-sexp-ignore-comments", &parse_sexp_ignore_comments, ! 1041: "Non-nil means forward-sexp, etc., should treat comments as whitespace.\n\ ! 1042: Non-nil works only when the comment terminator is something like *\/,\n\ ! 1043: and appears only when it ends a comment.\n\ ! 1044: If comments are terminated by newlines,\n\ ! 1045: you must make this variable nil."); ! 1046: ! 1047: defsubr (&Ssyntax_table_p); ! 1048: defsubr (&Ssyntax_table); ! 1049: defsubr (&Sstandard_syntax_table); ! 1050: defsubr (&Scopy_syntax_table); ! 1051: defsubr (&Sset_syntax_table); ! 1052: defsubr (&Schar_syntax); ! 1053: defsubr (&Smodify_syntax_entry); ! 1054: defsubr (&Sdescribe_syntax); ! 1055: ! 1056: defsubr (&Sforward_word); ! 1057: ! 1058: defsubr (&Sscan_lists); ! 1059: defsubr (&Sscan_sexps); ! 1060: defsubr (&Sbackward_prefix_chars); ! 1061: defsubr (&Sparse_partial_sexp); ! 1062: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.