comparison src/syntax.c @ 163:0f3996cb4ae5

Initial revision
author Richard M. Stallman <rms@gnu.org>
date Mon, 14 Jan 1991 01:21:14 +0000
parents
children 8c615e453683
comparison
equal deleted inserted replaced
162:6de3e4609f2c 163:0f3996cb4ae5
1 /* GNU Emacs routines to deal with syntax tables; also word and list parsing.
2 Copyright (C) 1985, 1987 Free Software Foundation, Inc.
3
4 This file is part of GNU Emacs.
5
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 1, or (at your option)
9 any later version.
10
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20
21 #include "config.h"
22 #include <ctype.h>
23 #include "lisp.h"
24 #include "commands.h"
25 #include "buffer.h"
26 #include "syntax.h"
27
28 Lisp_Object Qsyntax_table_p;
29
30 int words_include_escapes;
31
32 DEFUN ("syntax-table-p", Fsyntax_table_p, Ssyntax_table_p, 1, 1, 0,
33 "Return t if ARG is a syntax table.\n\
34 Any vector of 256 elements will do.")
35 (obj)
36 Lisp_Object obj;
37 {
38 if (XTYPE (obj) == Lisp_Vector && XVECTOR (obj)->size == 0400)
39 return Qt;
40 return Qnil;
41 }
42
43 Lisp_Object
44 check_syntax_table (obj)
45 Lisp_Object obj;
46 {
47 register Lisp_Object tem;
48 while (tem = Fsyntax_table_p (obj),
49 NULL (tem))
50 obj = wrong_type_argument (Qsyntax_table_p, obj, 0);
51 return obj;
52 }
53
54
55 DEFUN ("syntax-table", Fsyntax_table, Ssyntax_table, 0, 0, 0,
56 "Return the current syntax table.\n\
57 This is the one specified by the current buffer.")
58 ()
59 {
60 return current_buffer->syntax_table;
61 }
62
63 DEFUN ("standard-syntax-table", Fstandard_syntax_table,
64 Sstandard_syntax_table, 0, 0, 0,
65 "Return the standard syntax table.\n\
66 This is the one used for new buffers.")
67 ()
68 {
69 return Vstandard_syntax_table;
70 }
71
72 DEFUN ("copy-syntax-table", Fcopy_syntax_table, Scopy_syntax_table, 0, 1, 0,
73 "Construct a new syntax table and return it.\n\
74 It is a copy of the TABLE, which defaults to the standard syntax table.")
75 (table)
76 Lisp_Object table;
77 {
78 Lisp_Object size, val;
79 XFASTINT (size) = 0400;
80 XFASTINT (val) = 0;
81 val = Fmake_vector (size, val);
82 if (!NULL (table))
83 table = check_syntax_table (table);
84 else if (NULL (Vstandard_syntax_table))
85 /* Can only be null during initialization */
86 return val;
87 else table = Vstandard_syntax_table;
88
89 bcopy (XVECTOR (table)->contents,
90 XVECTOR (val)->contents, 0400 * sizeof (Lisp_Object));
91 return val;
92 }
93
94 DEFUN ("set-syntax-table", Fset_syntax_table, Sset_syntax_table, 1, 1, 0,
95 "Select a new syntax table for the current buffer.\n\
96 One argument, a syntax table.")
97 (table)
98 Lisp_Object table;
99 {
100 table = check_syntax_table (table);
101 current_buffer->syntax_table = table;
102 /* Indicate that this buffer now has a specified syntax table. */
103 current_buffer->local_var_flags |= buffer_local_flags.syntax_table;
104 return table;
105 }
106
107 /* Convert a letter which signifies a syntax code
108 into the code it signifies.
109 This is used by modify-syntax-entry, and other things. */
110
111 unsigned char syntax_spec_code[0400] =
112 { 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377,
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 (char) Swhitespace, 0377, (char) Sstring, 0377,
117 (char) Smath, 0377, 0377, (char) Squote,
118 (char) Sopen, (char) Sclose, 0377, 0377,
119 0377, (char) Swhitespace, (char) Spunct, (char) Scharquote,
120 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377,
121 0377, 0377, 0377, 0377,
122 (char) Scomment, 0377, (char) Sendcomment, 0377,
123 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, /* @, A, ... */
124 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377,
125 0377, 0377, 0377, 0377, 0377, 0377, 0377, (char) Sword,
126 0377, 0377, 0377, 0377, (char) Sescape, 0377, 0377, (char) Ssymbol,
127 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, /* `, a, ... */
128 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377,
129 0377, 0377, 0377, 0377, 0377, 0377, 0377, (char) Sword,
130 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377
131 };
132
133 /* Indexed by syntax code, give the letter that describes it. */
134
135 char syntax_code_spec[13] =
136 {
137 ' ', '.', 'w', '_', '(', ')', '\'', '\"', '$', '\\', '/', '<', '>'
138 };
139
140 DEFUN ("char-syntax", Fchar_syntax, Schar_syntax, 1, 1, 0,
141 "Return the syntax code of CHAR, described by a character.\n\
142 For example, if CHAR is a word constituent, the character `?w' is returned.\n\
143 The characters that correspond to various syntax codes\n\
144 are listed in the documentation of `modify-syntax-entry'.")
145 (ch)
146 Lisp_Object ch;
147 {
148 CHECK_NUMBER (ch, 0);
149 return make_number (syntax_code_spec[(int) SYNTAX (0xFF & XINT (ch))]);
150 }
151
152 /* This comment supplies the doc string for modify-syntax-entry,
153 for make-docfile to see. We cannot put this in the real DEFUN
154 due to limits in the Unix cpp.
155
156 DEFUN ("modify-syntax-entry", foo, bar, 0, 0, 0,
157 "Set syntax for character CHAR according to string S.\n\
158 The syntax is changed only for table TABLE, which defaults to\n\
159 the current buffer's syntax table.\n\
160 The first character of S should be one of the following:\n\
161 Space whitespace syntax. w word constituent.\n\
162 _ symbol constituent. . punctuation.\n\
163 ( open-parenthesis. ) close-parenthesis.\n\
164 \" string quote. \\ character-quote.\n\
165 $ paired delimiter. ' expression quote or prefix operator.\n\
166 < comment starter. > comment ender.\n\
167 Only single-character comment start and end sequences are represented thus.\n\
168 Two-character sequences are represented as described below.\n\
169 The second character of S is the matching parenthesis,\n\
170 used only if the first character is `(' or `)'.\n\
171 Any additional characters are flags.\n\
172 Defined flags are the characters 1, 2, 3, 4, and p.\n\
173 1 means C is the start of a two-char comment start sequence.\n\
174 2 means C is the second character of such a sequence.\n\
175 3 means C is the start of a two-char comment end sequence.\n\
176 4 means C is the second character of such a sequence.\n\
177 p means C is a prefix character for `backward-prefix-chars';
178 such characters are treated as whitespace when they occur
179 between expressions.")
180
181 */
182
183 DEFUN ("modify-syntax-entry", Fmodify_syntax_entry, Smodify_syntax_entry, 2, 3,
184 /* I really don't know why this is interactive
185 help-form should at least be made useful whilst reading the second arg
186 */
187 "cSet syntax for character: \nsSet syntax for %s to: ",
188 0 /* See immediately above */)
189 (c, newentry, syntax_table)
190 Lisp_Object c, newentry, syntax_table;
191 {
192 register unsigned char *p, match;
193 register enum syntaxcode code;
194 Lisp_Object val;
195
196 CHECK_NUMBER (c, 0);
197 CHECK_STRING (newentry, 1);
198 if (NULL (syntax_table))
199 syntax_table = current_buffer->syntax_table;
200 else
201 syntax_table = check_syntax_table (syntax_table);
202
203 p = XSTRING (newentry)->data;
204 code = (enum syntaxcode) syntax_spec_code[*p++];
205 if (((int) code & 0377) == 0377)
206 error ("invalid syntax description letter: %c", c);
207
208 match = *p;
209 if (match) p++;
210 if (match == ' ') match = 0;
211
212 XFASTINT (val) = (match << 8) + (int) code;
213 while (*p)
214 switch (*p++)
215 {
216 case '1':
217 XFASTINT (val) |= 1 << 16;
218 break;
219
220 case '2':
221 XFASTINT (val) |= 1 << 17;
222 break;
223
224 case '3':
225 XFASTINT (val) |= 1 << 18;
226 break;
227
228 case '4':
229 XFASTINT (val) |= 1 << 19;
230 break;
231
232 case 'p':
233 XFASTINT (val) |= 1 << 20;
234 break;
235 }
236
237 XVECTOR (syntax_table)->contents[0xFF & XINT (c)] = val;
238
239 return Qnil;
240 }
241
242 /* Dump syntax table to buffer in human-readable format */
243
244 describe_syntax (value)
245 Lisp_Object value;
246 {
247 register enum syntaxcode code;
248 char desc, match, start1, start2, end1, end2, prefix;
249 char str[2];
250
251 Findent_to (make_number (16), make_number (1));
252
253 if (XTYPE (value) != Lisp_Int)
254 {
255 insert_string ("invalid");
256 return;
257 }
258
259 code = (enum syntaxcode) (XINT (value) & 0377);
260 match = (XINT (value) >> 8) & 0377;
261 start1 = (XINT (value) >> 16) & 1;
262 start2 = (XINT (value) >> 17) & 1;
263 end1 = (XINT (value) >> 18) & 1;
264 end2 = (XINT (value) >> 19) & 1;
265 prefix = (XINT (value) >> 20) & 1;
266
267 if ((int) code < 0 || (int) code >= (int) Smax)
268 {
269 insert_string ("invalid");
270 return;
271 }
272 desc = syntax_code_spec[(int) code];
273
274 str[0] = desc, str[1] = 0;
275 insert (str, 1);
276
277 str[0] = match ? match : ' ';
278 insert (str, 1);
279
280
281 if (start1)
282 insert ("1", 1);
283 if (start2)
284 insert ("2", 1);
285
286 if (end1)
287 insert ("3", 1);
288 if (end2)
289 insert ("4", 1);
290
291 if (prefix)
292 insert ("p", 1);
293
294 insert_string ("\twhich means: ");
295
296 #ifdef SWITCH_ENUM_BUG
297 switch ((int) code)
298 #else
299 switch (code)
300 #endif
301 {
302 case Swhitespace:
303 insert_string ("whitespace"); break;
304 case Spunct:
305 insert_string ("punctuation"); break;
306 case Sword:
307 insert_string ("word"); break;
308 case Ssymbol:
309 insert_string ("symbol"); break;
310 case Sopen:
311 insert_string ("open"); break;
312 case Sclose:
313 insert_string ("close"); break;
314 case Squote:
315 insert_string ("quote"); break;
316 case Sstring:
317 insert_string ("string"); break;
318 case Smath:
319 insert_string ("math"); break;
320 case Sescape:
321 insert_string ("escape"); break;
322 case Scharquote:
323 insert_string ("charquote"); break;
324 case Scomment:
325 insert_string ("comment"); break;
326 case Sendcomment:
327 insert_string ("endcomment"); break;
328 default:
329 insert_string ("invalid");
330 return;
331 }
332
333 if (match)
334 {
335 insert_string (", matches ");
336
337 str[0] = match, str[1] = 0;
338 insert (str, 1);
339 }
340
341 if (start1)
342 insert_string (",\n\t is the first character of a comment-start sequence");
343 if (start2)
344 insert_string (",\n\t is the second character of a comment-start sequence");
345
346 if (end1)
347 insert_string (",\n\t is the first character of a comment-end sequence");
348 if (end2)
349 insert_string (",\n\t is the second character of a comment-end sequence");
350 if (prefix)
351 insert_string (",\n\t is a prefix character for `backward-prefix-chars'");
352
353 insert_string ("\n");
354 }
355
356 Lisp_Object
357 describe_syntax_1 (vector)
358 Lisp_Object vector;
359 {
360 struct buffer *old = current_buffer;
361 set_buffer_internal (XBUFFER (Vstandard_output));
362 describe_vector (vector, Qnil, describe_syntax, 0, Qnil, Qnil);
363 set_buffer_internal (old);
364 return Qnil;
365 }
366
367 DEFUN ("describe-syntax", Fdescribe_syntax, Sdescribe_syntax, 0, 0, "",
368 "Describe the syntax specifications in the syntax table.\n\
369 The descriptions are inserted in a buffer, which is then displayed.")
370 ()
371 {
372 internal_with_output_to_temp_buffer
373 ("*Help*", describe_syntax_1, current_buffer->syntax_table);
374
375 return Qnil;
376 }
377
378 /* Return the position across COUNT words from FROM.
379 If that many words cannot be found before the end of the buffer, return 0.
380 COUNT negative means scan backward and stop at word beginning. */
381
382 scan_words (from, count)
383 register int from, count;
384 {
385 register int beg = BEGV;
386 register int end = ZV;
387 register int code;
388
389 immediate_quit = 1;
390 QUIT;
391
392 while (count > 0)
393 {
394 while (1)
395 {
396 if (from == end)
397 {
398 immediate_quit = 0;
399 return 0;
400 }
401 code = SYNTAX (FETCH_CHAR (from));
402 if (words_include_escapes
403 && (code == Sescape || code == Scharquote))
404 break;
405 if (code == Sword)
406 break;
407 from++;
408 }
409 while (1)
410 {
411 if (from == end) break;
412 code = SYNTAX (FETCH_CHAR (from));
413 if (!(words_include_escapes
414 && (code == Sescape || code == Scharquote)))
415 if (code != Sword)
416 break;
417 from++;
418 }
419 count--;
420 }
421 while (count < 0)
422 {
423 while (1)
424 {
425 if (from == beg)
426 {
427 immediate_quit = 0;
428 return 0;
429 }
430 code = SYNTAX (FETCH_CHAR (from - 1));
431 if (words_include_escapes
432 && (code == Sescape || code == Scharquote))
433 break;
434 if (code == Sword)
435 break;
436 from--;
437 }
438 while (1)
439 {
440 if (from == beg) break;
441 code = SYNTAX (FETCH_CHAR (from - 1));
442 if (!(words_include_escapes
443 && (code == Sescape || code == Scharquote)))
444 if (code != Sword)
445 break;
446 from--;
447 }
448 count++;
449 }
450
451 immediate_quit = 0;
452
453 return from;
454 }
455
456 DEFUN ("forward-word", Fforward_word, Sforward_word, 1, 1, "p",
457 "Move point forward ARG words (backward if ARG is negative).\n\
458 Normally returns t.\n\
459 If an edge of the buffer is reached, point is left there\n\
460 and nil is returned.")
461 (count)
462 Lisp_Object count;
463 {
464 int val;
465 CHECK_NUMBER (count, 0);
466
467 if (!(val = scan_words (point, XINT (count))))
468 {
469 SET_PT (XINT (count) > 0 ? ZV : BEGV);
470 return Qnil;
471 }
472 SET_PT (val);
473 return Qt;
474 }
475
476 int parse_sexp_ignore_comments;
477
478 Lisp_Object
479 scan_lists (from, count, depth, sexpflag)
480 register int from;
481 int count, depth, sexpflag;
482 {
483 Lisp_Object val;
484 register int stop;
485 register int c;
486 char stringterm;
487 int quoted;
488 int mathexit = 0;
489 register enum syntaxcode code;
490 int min_depth = depth; /* Err out if depth gets less than this. */
491
492 if (depth > 0) min_depth = 0;
493
494 immediate_quit = 1;
495 QUIT;
496
497 while (count > 0)
498 {
499 stop = ZV;
500 while (from < stop)
501 {
502 c = FETCH_CHAR (from);
503 code = SYNTAX(c);
504 from++;
505 if (from < stop && SYNTAX_COMSTART_FIRST (c)
506 && SYNTAX_COMSTART_SECOND (FETCH_CHAR (from))
507 && parse_sexp_ignore_comments)
508 code = Scomment, from++;
509 if (SYNTAX_PREFIX (c))
510 continue;
511
512 #ifdef SWITCH_ENUM_BUG
513 switch ((int) code)
514 #else
515 switch (code)
516 #endif
517 {
518 case Sescape:
519 case Scharquote:
520 if (from == stop) goto lose;
521 from++;
522 /* treat following character as a word constituent */
523 case Sword:
524 case Ssymbol:
525 if (depth || !sexpflag) break;
526 /* This word counts as a sexp; return at end of it. */
527 while (from < stop)
528 {
529 #ifdef SWITCH_ENUM_BUG
530 switch ((int) SYNTAX(FETCH_CHAR (from)))
531 #else
532 switch (SYNTAX(FETCH_CHAR (from)))
533 #endif
534 {
535 case Scharquote:
536 case Sescape:
537 from++;
538 if (from == stop) goto lose;
539 break;
540 case Sword:
541 case Ssymbol:
542 case Squote:
543 break;
544 default:
545 goto done;
546 }
547 from++;
548 }
549 goto done;
550
551 case Scomment:
552 if (!parse_sexp_ignore_comments) break;
553 while (1)
554 {
555 if (from == stop) goto done;
556 if (SYNTAX (c = FETCH_CHAR (from)) == Sendcomment)
557 break;
558 from++;
559 if (from < stop && SYNTAX_COMEND_FIRST (c)
560 && SYNTAX_COMEND_SECOND (FETCH_CHAR (from)))
561 { from++; break; }
562 }
563 break;
564
565 case Smath:
566 if (!sexpflag)
567 break;
568 if (from != stop && c == FETCH_CHAR (from))
569 from++;
570 if (mathexit)
571 {
572 mathexit = 0;
573 goto close1;
574 }
575 mathexit = 1;
576
577 case Sopen:
578 if (!++depth) goto done;
579 break;
580
581 case Sclose:
582 close1:
583 if (!--depth) goto done;
584 if (depth < min_depth)
585 error ("Containing expression ends prematurely");
586 break;
587
588 case Sstring:
589 stringterm = FETCH_CHAR (from - 1);
590 while (1)
591 {
592 if (from >= stop) goto lose;
593 if (FETCH_CHAR (from) == stringterm) break;
594 #ifdef SWITCH_ENUM_BUG
595 switch ((int) SYNTAX(FETCH_CHAR (from)))
596 #else
597 switch (SYNTAX(FETCH_CHAR (from)))
598 #endif
599 {
600 case Scharquote:
601 case Sescape:
602 from++;
603 }
604 from++;
605 }
606 from++;
607 if (!depth && sexpflag) goto done;
608 break;
609 }
610 }
611
612 /* Reached end of buffer. Error if within object, return nil if between */
613 if (depth) goto lose;
614
615 immediate_quit = 0;
616 return Qnil;
617
618 /* End of object reached */
619 done:
620 count--;
621 }
622
623 while (count < 0)
624 {
625 stop = BEGV;
626 while (from > stop)
627 {
628 from--;
629 if (quoted = char_quoted (from))
630 from--;
631 c = FETCH_CHAR (from);
632 code = SYNTAX (c);
633 if (from > stop && SYNTAX_COMEND_SECOND (c)
634 && SYNTAX_COMEND_FIRST (FETCH_CHAR (from - 1))
635 && !char_quoted (from - 1)
636 && parse_sexp_ignore_comments)
637 code = Sendcomment, from--;
638 if (SYNTAX_PREFIX (c))
639 continue;
640
641 #ifdef SWITCH_ENUM_BUG
642 switch ((int) (quoted ? Sword : code))
643 #else
644 switch (quoted ? Sword : code)
645 #endif
646 {
647 case Sword:
648 case Ssymbol:
649 if (depth || !sexpflag) break;
650 /* This word counts as a sexp; count object finished after passing it. */
651 while (from > stop)
652 {
653 quoted = char_quoted (from - 1);
654 if (quoted)
655 from--;
656 if (! (quoted || SYNTAX(FETCH_CHAR (from - 1)) == Sword
657 || SYNTAX(FETCH_CHAR (from - 1)) == Ssymbol
658 || SYNTAX(FETCH_CHAR (from - 1)) == Squote))
659 goto done2;
660 from--;
661 }
662 goto done2;
663
664 case Smath:
665 if (!sexpflag)
666 break;
667 if (from != stop && c == FETCH_CHAR (from - 1))
668 from--;
669 if (mathexit)
670 {
671 mathexit = 0;
672 goto open2;
673 }
674 mathexit = 1;
675
676 case Sclose:
677 if (!++depth) goto done2;
678 break;
679
680 case Sopen:
681 open2:
682 if (!--depth) goto done2;
683 if (depth < min_depth)
684 error ("Containing expression ends prematurely");
685 break;
686
687 case Sendcomment:
688 if (!parse_sexp_ignore_comments)
689 break;
690 /* Look back, counting the parity of string-quotes,
691 and recording the comment-starters seen.
692 When we reach a safe place, assume that's not in a string;
693 then step the main scan to the earliest comment-starter seen
694 an even number of string quotes away from the safe place.
695
696 OFROM[I] is position of the earliest comment-starter seen
697 which is I+2X quotes from the comment-end.
698 PARITY is current parity of quotes from the comment end. */
699 {
700 int ofrom[2];
701 int parity = 0;
702
703 ofrom[0] = ofrom[1] = from;
704
705 /* At beginning of range to scan, we're outside of strings;
706 that determines quote parity to the comment-end. */
707 while (from != stop)
708 {
709 /* Move back and examine a character. */
710 from--;
711
712 c = FETCH_CHAR (from);
713 code = SYNTAX (c);
714
715 /* If this char is the second of a 2-char comment sequence,
716 back up and give the pair the appropriate syntax. */
717 if (from > stop && SYNTAX_COMEND_SECOND (c)
718 && SYNTAX_COMEND_FIRST (FETCH_CHAR (from - 1)))
719 code = Sendcomment, from--;
720 else if (from > stop && SYNTAX_COMSTART_SECOND (c)
721 && SYNTAX_COMSTART_FIRST (FETCH_CHAR (from - 1)))
722 code = Scomment, from--;
723
724 /* Ignore escaped characters. */
725 if (char_quoted (from))
726 continue;
727
728 /* Track parity of quotes between here and comment-end. */
729 if (code == Sstring)
730 parity ^= 1;
731
732 /* Record comment-starters according to that
733 quote-parity to the comment-end. */
734 if (code == Scomment)
735 ofrom[parity] = from;
736
737 /* If we come to another comment-end,
738 assume it's not inside a string.
739 That determines the quote parity to the comment-end. */
740 if (code == Sendcomment)
741 break;
742 }
743 from = ofrom[parity];
744 }
745 break;
746
747 case Sstring:
748 stringterm = FETCH_CHAR (from);
749 while (1)
750 {
751 if (from == stop) goto lose;
752 if (!char_quoted (from - 1)
753 && stringterm == FETCH_CHAR (from - 1))
754 break;
755 from--;
756 }
757 from--;
758 if (!depth && sexpflag) goto done2;
759 break;
760 }
761 }
762
763 /* Reached start of buffer. Error if within object, return nil if between */
764 if (depth) goto lose;
765
766 immediate_quit = 0;
767 return Qnil;
768
769 done2:
770 count++;
771 }
772
773
774 immediate_quit = 0;
775 XFASTINT (val) = from;
776 return val;
777
778 lose:
779 error ("Unbalanced parentheses");
780 /* NOTREACHED */
781 }
782
783 char_quoted (pos)
784 register int pos;
785 {
786 register enum syntaxcode code;
787 register int beg = BEGV;
788 register int quoted = 0;
789
790 while (pos > beg
791 && ((code = SYNTAX (FETCH_CHAR (pos - 1))) == Scharquote
792 || code == Sescape))
793 pos--, quoted = !quoted;
794 return quoted;
795 }
796
797 DEFUN ("scan-lists", Fscan_lists, Sscan_lists, 3, 3, 0,
798 "Scan from character number FROM by COUNT lists.\n\
799 Returns the character number of the position thus found.\n\
800 \n\
801 If DEPTH is nonzero, paren depth begins counting from that value,\n\
802 only places where the depth in parentheses becomes zero\n\
803 are candidates for stopping; COUNT such places are counted.\n\
804 Thus, a positive value for DEPTH means go out levels.\n\
805 \n\
806 Comments are ignored if `parse-sexp-ignore-comments' is non-nil.\n\
807 \n\
808 If the beginning or end of (the accessible part of) the buffer is reached\n\
809 and the depth is wrong, an error is signaled.\n\
810 If the depth is right but the count is not used up, nil is returned.")
811 (from, count, depth)
812 Lisp_Object from, count, depth;
813 {
814 CHECK_NUMBER (from, 0);
815 CHECK_NUMBER (count, 1);
816 CHECK_NUMBER (depth, 2);
817
818 return scan_lists (XINT (from), XINT (count), XINT (depth), 0);
819 }
820
821 DEFUN ("scan-sexps", Fscan_sexps, Sscan_sexps, 2, 2, 0,
822 "Scan from character number FROM by COUNT balanced expressions.\n\
823 If COUNT is negative, scan backwards.\n\
824 Returns the character number of the position thus found.\n\
825 \n\
826 Comments are ignored if `parse-sexp-ignore-comments' is non-nil.\n\
827 \n\
828 If the beginning or end of (the accessible part of) the buffer is reached\n\
829 in the middle of a parenthetical grouping, an error is signaled.\n\
830 If the beginning or end is reached between groupings\n\
831 but before count is used up, nil is returned.")
832 (from, count)
833 Lisp_Object from, count;
834 {
835 CHECK_NUMBER (from, 0);
836 CHECK_NUMBER (count, 1);
837
838 return scan_lists (XINT (from), XINT (count), 0, 1);
839 }
840
841 DEFUN ("backward-prefix-chars", Fbackward_prefix_chars, Sbackward_prefix_chars,
842 0, 0, 0,
843 "Move point backward over any number of chars with prefix syntax.\n\
844 This includes chars with \"quote\" or \"prefix\" syntax (' or p).")
845 ()
846 {
847 int beg = BEGV;
848 int pos = point;
849
850 while (pos > beg && !char_quoted (pos - 1)
851 && (SYNTAX (FETCH_CHAR (pos - 1)) == Squote
852 || SYNTAX_PREFIX (FETCH_CHAR (pos - 1))))
853 pos--;
854
855 SET_PT (pos);
856
857 return Qnil;
858 }
859
860 struct lisp_parse_state
861 {
862 int depth; /* Depth at end of parsing */
863 int instring; /* -1 if not within string, else desired terminator. */
864 int incomment; /* Nonzero if within a comment at end of parsing */
865 int quoted; /* Nonzero if just after an escape char at end of parsing */
866 int thislevelstart; /* Char number of most recent start-of-expression at current level */
867 int prevlevelstart; /* Char number of start of containing expression */
868 int location; /* Char number at which parsing stopped. */
869 int mindepth; /* Minimum depth seen while scanning. */
870 };
871
872 /* Parse forward from FROM to END,
873 assuming that FROM is the start of a function,
874 and return a description of the state of the parse at END. */
875
876 struct lisp_parse_state val_scan_sexps_forward;
877
878 struct lisp_parse_state *
879 scan_sexps_forward (from, end, targetdepth, stopbefore, oldstate)
880 register int from;
881 int end, targetdepth, stopbefore;
882 Lisp_Object oldstate;
883 {
884 struct lisp_parse_state state;
885
886 register enum syntaxcode code;
887 struct level { int last, prev; };
888 struct level levelstart[100];
889 register struct level *curlevel = levelstart;
890 struct level *endlevel = levelstart + 100;
891 char prev;
892 register int depth; /* Paren depth of current scanning location.
893 level - levelstart equals this except
894 when the depth becomes negative. */
895 int mindepth; /* Lowest DEPTH value seen. */
896 int start_quoted = 0; /* Nonzero means starting after a char quote */
897 Lisp_Object tem;
898
899 immediate_quit = 1;
900 QUIT;
901
902 if (NULL (oldstate))
903 {
904 depth = 0;
905 state.instring = -1;
906 state.incomment = 0;
907 }
908 else
909 {
910 tem = Fcar (oldstate);
911 if (!NULL (tem))
912 depth = XINT (tem);
913 else
914 depth = 0;
915
916 oldstate = Fcdr (oldstate);
917 oldstate = Fcdr (oldstate);
918 oldstate = Fcdr (oldstate);
919 tem = Fcar (oldstate);
920 state.instring = !NULL (tem) ? XINT (tem) : -1;
921
922 oldstate = Fcdr (oldstate);
923 tem = Fcar (oldstate);
924 state.incomment = !NULL (tem);
925
926 oldstate = Fcdr (oldstate);
927 tem = Fcar (oldstate);
928 start_quoted = !NULL (tem);
929 }
930 state.quoted = 0;
931 mindepth = depth;
932
933 curlevel->prev = -1;
934 curlevel->last = -1;
935
936 /* Enter the loop at a place appropriate for initial state. */
937
938 if (state.incomment) goto startincomment;
939 if (state.instring >= 0)
940 {
941 if (start_quoted) goto startquotedinstring;
942 goto startinstring;
943 }
944 if (start_quoted) goto startquoted;
945
946 while (from < end)
947 {
948 code = SYNTAX(FETCH_CHAR (from));
949 from++;
950 if (from < end && SYNTAX_COMSTART_FIRST (FETCH_CHAR (from - 1))
951 && SYNTAX_COMSTART_SECOND (FETCH_CHAR (from)))
952 code = Scomment, from++;
953 if (SYNTAX_PREFIX (FETCH_CHAR (from - 1)))
954 continue;
955 #ifdef SWITCH_ENUM_BUG
956 switch ((int) code)
957 #else
958 switch (code)
959 #endif
960 {
961 case Sescape:
962 case Scharquote:
963 if (stopbefore) goto stop; /* this arg means stop at sexp start */
964 curlevel->last = from - 1;
965 startquoted:
966 if (from == end) goto endquoted;
967 from++;
968 goto symstarted;
969 /* treat following character as a word constituent */
970 case Sword:
971 case Ssymbol:
972 if (stopbefore) goto stop; /* this arg means stop at sexp start */
973 curlevel->last = from - 1;
974 symstarted:
975 while (from < end)
976 {
977 #ifdef SWITCH_ENUM_BUG
978 switch ((int) SYNTAX(FETCH_CHAR (from)))
979 #else
980 switch (SYNTAX(FETCH_CHAR (from)))
981 #endif
982 {
983 case Scharquote:
984 case Sescape:
985 from++;
986 if (from == end) goto endquoted;
987 break;
988 case Sword:
989 case Ssymbol:
990 case Squote:
991 break;
992 default:
993 goto symdone;
994 }
995 from++;
996 }
997 symdone:
998 curlevel->prev = curlevel->last;
999 break;
1000
1001 case Scomment:
1002 state.incomment = 1;
1003 startincomment:
1004 while (1)
1005 {
1006 if (from == end) goto done;
1007 if (SYNTAX (prev = FETCH_CHAR (from)) == Sendcomment)
1008 break;
1009 from++;
1010 if (from < end && SYNTAX_COMEND_FIRST (prev)
1011 && SYNTAX_COMEND_SECOND (FETCH_CHAR (from)))
1012 { from++; break; }
1013 }
1014 state.incomment = 0;
1015 break;
1016
1017 case Sopen:
1018 if (stopbefore) goto stop; /* this arg means stop at sexp start */
1019 depth++;
1020 /* curlevel++->last ran into compiler bug on Apollo */
1021 curlevel->last = from - 1;
1022 if (++curlevel == endlevel)
1023 error ("Nesting too deep for parser");
1024 curlevel->prev = -1;
1025 curlevel->last = -1;
1026 if (!--targetdepth) goto done;
1027 break;
1028
1029 case Sclose:
1030 depth--;
1031 if (depth < mindepth)
1032 mindepth = depth;
1033 if (curlevel != levelstart)
1034 curlevel--;
1035 curlevel->prev = curlevel->last;
1036 if (!++targetdepth) goto done;
1037 break;
1038
1039 case Sstring:
1040 if (stopbefore) goto stop; /* this arg means stop at sexp start */
1041 curlevel->last = from - 1;
1042 state.instring = FETCH_CHAR (from - 1);
1043 startinstring:
1044 while (1)
1045 {
1046 if (from >= end) goto done;
1047 if (FETCH_CHAR (from) == state.instring) break;
1048 #ifdef SWITCH_ENUM_BUG
1049 switch ((int) SYNTAX(FETCH_CHAR (from)))
1050 #else
1051 switch (SYNTAX(FETCH_CHAR (from)))
1052 #endif
1053 {
1054 case Scharquote:
1055 case Sescape:
1056 from++;
1057 startquotedinstring:
1058 if (from >= end) goto endquoted;
1059 }
1060 from++;
1061 }
1062 state.instring = -1;
1063 curlevel->prev = curlevel->last;
1064 from++;
1065 break;
1066
1067 case Smath:
1068 break;
1069 }
1070 }
1071 goto done;
1072
1073 stop: /* Here if stopping before start of sexp. */
1074 from--; /* We have just fetched the char that starts it; */
1075 goto done; /* but return the position before it. */
1076
1077 endquoted:
1078 state.quoted = 1;
1079 done:
1080 state.depth = depth;
1081 state.mindepth = mindepth;
1082 state.thislevelstart = curlevel->prev;
1083 state.prevlevelstart
1084 = (curlevel == levelstart) ? -1 : (curlevel - 1)->last;
1085 state.location = from;
1086 immediate_quit = 0;
1087
1088 val_scan_sexps_forward = state;
1089 return &val_scan_sexps_forward;
1090 }
1091
1092 /* This comment supplies the doc string for parse-partial-sexp,
1093 for make-docfile to see. We cannot put this in the real DEFUN
1094 due to limits in the Unix cpp.
1095
1096 DEFUN ("parse-partial-sexp", Ffoo, Sfoo, 0, 0, 0,
1097 "Parse Lisp syntax starting at FROM until TO; return status of parse at TO.\n\
1098 Parsing stops at TO or when certain criteria are met;\n\
1099 point is set to where parsing stops.\n\
1100 If fifth arg STATE is omitted or nil,\n\
1101 parsing assumes that FROM is the beginning of a function.\n\
1102 Value is a list of seven elements describing final state of parsing:\n\
1103 1. depth in parens.\n\
1104 2. character address of start of innermost containing list; nil if none.\n\
1105 3. character address of start of last complete sexp terminated.\n\
1106 4. non-nil if inside a string.\n\
1107 (it is the character that will terminate the string.)\n\
1108 5. t if inside a comment.\n\
1109 6. t if following a quote character.\n\
1110 7. the minimum paren-depth encountered during this scan.\n\
1111 If third arg TARGETDEPTH is non-nil, parsing stops if the depth\n\
1112 in parentheses becomes equal to TARGETDEPTH.\n\
1113 Fourth arg STOPBEFORE non-nil means stop when come to\n\
1114 any character that starts a sexp.\n\
1115 Fifth arg STATE is a seven-list like what this function returns.\n\
1116 It is used to initialize the state of the parse.")
1117
1118 */
1119
1120 DEFUN ("parse-partial-sexp", Fparse_partial_sexp, Sparse_partial_sexp, 2, 5, 0,
1121 0 /* See immediately above */)
1122 (from, to, targetdepth, stopbefore, oldstate)
1123 Lisp_Object from, to, targetdepth, stopbefore, oldstate;
1124 {
1125 struct lisp_parse_state state;
1126 int target;
1127
1128 if (!NULL (targetdepth))
1129 {
1130 CHECK_NUMBER (targetdepth, 3);
1131 target = XINT (targetdepth);
1132 }
1133 else
1134 target = -100000; /* We won't reach this depth */
1135
1136 validate_region (&from, &to);
1137 state = *scan_sexps_forward (XINT (from), XINT (to),
1138 target, !NULL (stopbefore), oldstate);
1139
1140 SET_PT (state.location);
1141
1142 return Fcons (make_number (state.depth),
1143 Fcons (state.prevlevelstart < 0 ? Qnil : make_number (state.prevlevelstart),
1144 Fcons (state.thislevelstart < 0 ? Qnil : make_number (state.thislevelstart),
1145 Fcons (state.instring >= 0 ? make_number (state.instring) : Qnil,
1146 Fcons (state.incomment ? Qt : Qnil,
1147 Fcons (state.quoted ? Qt : Qnil,
1148 Fcons (make_number (state.mindepth), Qnil)))))));
1149 }
1150
1151 init_syntax_once ()
1152 {
1153 register int i;
1154 register struct Lisp_Vector *v;
1155
1156 /* Set this now, so first buffer creation can refer to it. */
1157 /* Make it nil before calling copy-syntax-table
1158 so that copy-syntax-table will know not to try to copy from garbage */
1159 Vstandard_syntax_table = Qnil;
1160 Vstandard_syntax_table = Fcopy_syntax_table (Qnil);
1161
1162 v = XVECTOR (Vstandard_syntax_table);
1163
1164 for (i = 'a'; i <= 'z'; i++)
1165 XFASTINT (v->contents[i]) = (int) Sword;
1166 for (i = 'A'; i <= 'Z'; i++)
1167 XFASTINT (v->contents[i]) = (int) Sword;
1168 for (i = '0'; i <= '9'; i++)
1169 XFASTINT (v->contents[i]) = (int) Sword;
1170 XFASTINT (v->contents['$']) = (int) Sword;
1171 XFASTINT (v->contents['%']) = (int) Sword;
1172
1173 XFASTINT (v->contents['(']) = (int) Sopen + (')' << 8);
1174 XFASTINT (v->contents[')']) = (int) Sclose + ('(' << 8);
1175 XFASTINT (v->contents['[']) = (int) Sopen + (']' << 8);
1176 XFASTINT (v->contents[']']) = (int) Sclose + ('[' << 8);
1177 XFASTINT (v->contents['{']) = (int) Sopen + ('}' << 8);
1178 XFASTINT (v->contents['}']) = (int) Sclose + ('{' << 8);
1179 XFASTINT (v->contents['"']) = (int) Sstring;
1180 XFASTINT (v->contents['\\']) = (int) Sescape;
1181
1182 for (i = 0; i < 10; i++)
1183 XFASTINT (v->contents["_-+*/&|<>="[i]]) = (int) Ssymbol;
1184
1185 for (i = 0; i < 12; i++)
1186 XFASTINT (v->contents[".,;:?!#@~^'`"[i]]) = (int) Spunct;
1187 }
1188
1189 syms_of_syntax ()
1190 {
1191 Qsyntax_table_p = intern ("syntax-table-p");
1192 staticpro (&Qsyntax_table_p);
1193
1194 DEFVAR_BOOL ("parse-sexp-ignore-comments", &parse_sexp_ignore_comments,
1195 "Non-nil means `forward-sexp', etc., should treat comments as whitespace.");
1196
1197 words_include_escapes = 0;
1198 DEFVAR_BOOL ("words-include-escapes", &words_include_escapes,
1199 "Non-nil means `forward-word', etc., should treat escape chars part of words.");
1200
1201 defsubr (&Ssyntax_table_p);
1202 defsubr (&Ssyntax_table);
1203 defsubr (&Sstandard_syntax_table);
1204 defsubr (&Scopy_syntax_table);
1205 defsubr (&Sset_syntax_table);
1206 defsubr (&Schar_syntax);
1207 defsubr (&Smodify_syntax_entry);
1208 defsubr (&Sdescribe_syntax);
1209
1210 defsubr (&Sforward_word);
1211
1212 defsubr (&Sscan_lists);
1213 defsubr (&Sscan_sexps);
1214 defsubr (&Sbackward_prefix_chars);
1215 defsubr (&Sparse_partial_sexp);
1216 }