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: }

Defined functions

DEFUN defined in line 961; never used
char_quoted defined in line 667; used 6 times
check_syntax_table defined in line 44; used 3 times
describe_syntax defined in line 209; used 1 times
describe_syntax_1 defined in line 311; used 1 times
init_syntax_once defined in line 991; used 1 times
scan_lists defined in line 421; used 2 times
scan_sexps_forward defined in line 756; used 1 times
scan_words defined in line 340; used 5 times
syms_of_syntax defined in line 1029; used 1 times

Defined variables

Qsyntax_table_p defined in line 29; used 3 times
Vstandard_syntax_table defined in line 29; used 7 times
parse_sexp_ignore_comments defined in line 419; used 5 times
syntax_code_spec defined in line 136; used 2 times
syntax_spec_code defined in line 112; used 1 times
val_scan_sexps_forward defined in line 754; used 2 times

Defined struct's

level defined in line 765; used 6 times
lisp_parse_state defined in line 740; used 8 times
Last modified: 1986-03-11
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2320
Valid CSS Valid XHTML 1.0 Strict