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