(Fminibuffer_message): New function.
[bpt/emacs.git] / src / syntax.c
CommitLineData
8489eb67 1/* GNU Emacs routines to deal with syntax tables; also word and list parsing.
0220c518 2 Copyright (C) 1985, 1987, 1993, 1994, 1995 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
3b7ad313
EN
18the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, USA. */
8489eb67
RS
20
21
18160b98 22#include <config.h>
8489eb67
RS
23#include <ctype.h>
24#include "lisp.h"
25#include "commands.h"
26#include "buffer.h"
27#include "syntax.h"
28
5ebaddf5 29Lisp_Object Qsyntax_table_p, Qsyntax_table;
8489eb67 30
340f92b5
RS
31static void scan_sexps_forward ();
32static int char_quoted ();
33
8489eb67
RS
34int words_include_escapes;
35
8ea151b2
RS
36/* Used as a temporary in SYNTAX_ENTRY and other macros in syntax.h,
37 if not compiled with GCC. No need to mark it, since it is used
38 only very temporarily. */
39Lisp_Object syntax_temp;
40
e5d4f4dc
RS
41/* This is the internal form of the parse state used in parse-partial-sexp. */
42
43struct lisp_parse_state
44 {
45 int depth; /* Depth at end of parsing */
46 int instring; /* -1 if not within string, else desired terminator. */
47 int incomment; /* Nonzero if within a comment at end of parsing */
48 int comstyle; /* comment style a=0, or b=1 */
49 int quoted; /* Nonzero if just after an escape char at end of parsing */
50 int thislevelstart; /* Char number of most recent start-of-expression at current level */
51 int prevlevelstart; /* Char number of start of containing expression */
52 int location; /* Char number at which parsing stopped. */
53 int mindepth; /* Minimum depth seen while scanning. */
54 int comstart; /* Position just after last comment starter. */
55 };
56\f
37bef230
RS
57/* These variables are a cache for finding the start of a defun.
58 find_start_pos is the place for which the defun start was found.
59 find_start_value is the defun start position found for it.
60 find_start_buffer is the buffer it was found in.
61 find_start_begv is the BEGV value when it was found.
62 find_start_modiff is the value of MODIFF when it was found. */
63
64static int find_start_pos;
65static int find_start_value;
66static struct buffer *find_start_buffer;
67static int find_start_begv;
68static int find_start_modiff;
69
70/* Find a defun-start that is the last one before POS (or nearly the last).
71 We record what we find, so that another call in the same area
72 can return the same value right away. */
73
74static int
75find_defun_start (pos)
76 int pos;
77{
78 int tem;
79 int shortage;
80
81 /* Use previous finding, if it's valid and applies to this inquiry. */
82 if (current_buffer == find_start_buffer
83 /* Reuse the defun-start even if POS is a little farther on.
84 POS might be in the next defun, but that's ok.
85 Our value may not be the best possible, but will still be usable. */
86 && pos <= find_start_pos + 1000
87 && pos >= find_start_value
88 && BEGV == find_start_begv
89 && MODIFF == find_start_modiff)
90 return find_start_value;
91
92 /* Back up to start of line. */
be5357e2 93 tem = scan_buffer ('\n', pos, BEGV, -1, &shortage, 1);
37bef230
RS
94
95 while (tem > BEGV)
96 {
97 /* Open-paren at start of line means we found our defun-start. */
98 if (SYNTAX (FETCH_CHAR (tem)) == Sopen)
99 break;
100 /* Move to beg of previous line. */
be5357e2 101 tem = scan_buffer ('\n', tem, BEGV, -2, &shortage, 1);
37bef230
RS
102 }
103
104 /* Record what we found, for the next try. */
105 find_start_value = tem;
106 find_start_buffer = current_buffer;
107 find_start_modiff = MODIFF;
108 find_start_begv = BEGV;
109 find_start_pos = pos;
110
111 return find_start_value;
112}
113\f
8489eb67 114DEFUN ("syntax-table-p", Fsyntax_table_p, Ssyntax_table_p, 1, 1, 0,
2203e1e8 115 "Return t if OBJECT is a syntax table.\n\
8ea151b2 116Currently, any char-table counts as a syntax table.")
2203e1e8
EN
117 (object)
118 Lisp_Object object;
8489eb67 119{
2203e1e8
EN
120 if (CHAR_TABLE_P (object)
121 && XCHAR_TABLE (object)->purpose == Qsyntax_table)
8489eb67
RS
122 return Qt;
123 return Qnil;
124}
125
8ea151b2 126static void
8489eb67
RS
127check_syntax_table (obj)
128 Lisp_Object obj;
129{
d1be9f0f
RS
130 if (!(CHAR_TABLE_P (obj)
131 && XCHAR_TABLE (obj)->purpose == Qsyntax_table))
132 wrong_type_argument (Qsyntax_table_p, obj);
8489eb67
RS
133}
134
8489eb67
RS
135DEFUN ("syntax-table", Fsyntax_table, Ssyntax_table, 0, 0, 0,
136 "Return the current syntax table.\n\
137This is the one specified by the current buffer.")
138 ()
139{
140 return current_buffer->syntax_table;
141}
142
143DEFUN ("standard-syntax-table", Fstandard_syntax_table,
144 Sstandard_syntax_table, 0, 0, 0,
145 "Return the standard syntax table.\n\
146This is the one used for new buffers.")
147 ()
148{
149 return Vstandard_syntax_table;
150}
151
152DEFUN ("copy-syntax-table", Fcopy_syntax_table, Scopy_syntax_table, 0, 1, 0,
153 "Construct a new syntax table and return it.\n\
154It is a copy of the TABLE, which defaults to the standard syntax table.")
155 (table)
156 Lisp_Object table;
157{
8ea151b2
RS
158 Lisp_Object copy;
159
265a9e55 160 if (!NILP (table))
8ea151b2
RS
161 check_syntax_table (table);
162 else
163 table = Vstandard_syntax_table;
164
165 copy = Fcopy_sequence (table);
0f867324
RS
166
167 /* Only the standard syntax table should have a default element.
168 Other syntax tables should inherit from parents instead. */
169 XCHAR_TABLE (copy)->defalt = Qnil;
170
171 /* Copied syntax tables should all have parents.
172 If we copied one with no parent, such as the standard syntax table,
173 use the standard syntax table as the copy's parent. */
174 if (NILP (XCHAR_TABLE (copy)->parent))
175 Fset_char_table_parent (copy, Vstandard_syntax_table);
8ea151b2 176 return copy;
8489eb67
RS
177}
178
179DEFUN ("set-syntax-table", Fset_syntax_table, Sset_syntax_table, 1, 1, 0,
180 "Select a new syntax table for the current buffer.\n\
181One argument, a syntax table.")
182 (table)
183 Lisp_Object table;
184{
8ea151b2 185 check_syntax_table (table);
8489eb67
RS
186 current_buffer->syntax_table = table;
187 /* Indicate that this buffer now has a specified syntax table. */
f110a664
RS
188 current_buffer->local_var_flags
189 |= XFASTINT (buffer_local_flags.syntax_table);
8489eb67
RS
190 return table;
191}
192\f
193/* Convert a letter which signifies a syntax code
194 into the code it signifies.
195 This is used by modify-syntax-entry, and other things. */
196
197unsigned char syntax_spec_code[0400] =
198 { 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377,
199 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377,
200 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377,
201 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377,
202 (char) Swhitespace, 0377, (char) Sstring, 0377,
203 (char) Smath, 0377, 0377, (char) Squote,
204 (char) Sopen, (char) Sclose, 0377, 0377,
205 0377, (char) Swhitespace, (char) Spunct, (char) Scharquote,
206 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377,
207 0377, 0377, 0377, 0377,
208 (char) Scomment, 0377, (char) Sendcomment, 0377,
6cb71bf6 209 (char) Sinherit, 0377, 0377, 0377, 0377, 0377, 0377, 0377, /* @, A ... */
8489eb67
RS
210 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377,
211 0377, 0377, 0377, 0377, 0377, 0377, 0377, (char) Sword,
212 0377, 0377, 0377, 0377, (char) Sescape, 0377, 0377, (char) Ssymbol,
213 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, /* `, a, ... */
214 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377,
215 0377, 0377, 0377, 0377, 0377, 0377, 0377, (char) Sword,
216 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377
217 };
218
219/* Indexed by syntax code, give the letter that describes it. */
220
6cb71bf6 221char syntax_code_spec[14] =
8489eb67 222 {
6cb71bf6 223 ' ', '.', 'w', '_', '(', ')', '\'', '\"', '$', '\\', '/', '<', '>', '@'
8489eb67
RS
224 };
225\f
8ea151b2
RS
226/* Look up the value for CHARACTER in syntax table TABLE's parent
227 and its parents. SYNTAX_ENTRY calls this, when TABLE itself has nil
228 for CHARACTER. It's actually used only when not compiled with GCC. */
229
230Lisp_Object
231syntax_parent_lookup (table, character)
232 Lisp_Object table;
233 int character;
234{
235 Lisp_Object value;
236
237 while (1)
238 {
239 table = XCHAR_TABLE (table)->parent;
240 if (NILP (table))
241 return Qnil;
242
243 value = XCHAR_TABLE (table)->contents[character];
244 if (!NILP (value))
245 return value;
246 }
247}
248
8489eb67 249DEFUN ("char-syntax", Fchar_syntax, Schar_syntax, 1, 1, 0,
2203e1e8
EN
250 "Return the syntax code of CHARACTER, described by a character.\n\
251For example, if CHARACTER is a word constituent,\n\
252the character `w' is returned.\n\
8489eb67
RS
253The characters that correspond to various syntax codes\n\
254are listed in the documentation of `modify-syntax-entry'.")
2203e1e8
EN
255 (character)
256 Lisp_Object character;
8489eb67 257{
8ea151b2 258 int char_int;
2203e1e8
EN
259 CHECK_NUMBER (character, 0);
260 char_int = XINT (character);
8ea151b2 261 return make_number (syntax_code_spec[(int) SYNTAX (char_int)]);
beefa22e
RS
262}
263
264DEFUN ("matching-paren", Fmatching_paren, Smatching_paren, 1, 1, 0,
2203e1e8
EN
265 "Return the matching parenthesis of CHARACTER, or nil if none.")
266 (character)
267 Lisp_Object character;
beefa22e 268{
8ea151b2 269 int char_int, code;
2203e1e8
EN
270 CHECK_NUMBER (character, 0);
271 char_int = XINT (character);
8ea151b2 272 code = SYNTAX (char_int);
a8bd7cd8 273 if (code == Sopen || code == Sclose)
8ea151b2 274 return make_number (SYNTAX_MATCH (char_int));
beefa22e 275 return Qnil;
8489eb67
RS
276}
277
278/* This comment supplies the doc string for modify-syntax-entry,
279 for make-docfile to see. We cannot put this in the real DEFUN
280 due to limits in the Unix cpp.
281
2fcea188 282DEFUN ("modify-syntax-entry", foo, bar, 2, 3, 0,
8489eb67
RS
283 "Set syntax for character CHAR according to string S.\n\
284The syntax is changed only for table TABLE, which defaults to\n\
285 the current buffer's syntax table.\n\
286The first character of S should be one of the following:\n\
32676c08
JB
287 Space or - whitespace syntax. w word constituent.\n\
288 _ symbol constituent. . punctuation.\n\
289 ( open-parenthesis. ) close-parenthesis.\n\
290 \" string quote. \\ escape.\n\
291 $ paired delimiter. ' expression quote or prefix operator.\n\
abae13bd 292 < comment starter. > comment ender.\n\
6cb71bf6 293 / character-quote. @ inherit from `standard-syntax-table'.\n\
abae13bd 294\n\
8489eb67
RS
295Only single-character comment start and end sequences are represented thus.\n\
296Two-character sequences are represented as described below.\n\
297The second character of S is the matching parenthesis,\n\
298 used only if the first character is `(' or `)'.\n\
299Any additional characters are flags.\n\
e5d4f4dc 300Defined flags are the characters 1, 2, 3, 4, b, and p.\n\
2203e1e8
EN
301 1 means CHAR is the start of a two-char comment start sequence.\n\
302 2 means CHAR is the second character of such a sequence.\n\
303 3 means CHAR is the start of a two-char comment end sequence.\n\
304 4 means CHAR is the second character of such a sequence.\n\
e5d4f4dc
RS
305\n\
306There can be up to two orthogonal comment sequences. This is to support\n\
307language modes such as C++. By default, all comment sequences are of style\n\
abae13bd
RS
308a, but you can set the comment sequence style to b (on the second character\n\
309of a comment-start, or the first character of a comment-end sequence) using\n\
e5d4f4dc 310this flag:\n\
2203e1e8 311 b means CHAR is part of comment sequence b.\n\
e5d4f4dc 312\n\
2203e1e8 313 p means CHAR is a prefix character for `backward-prefix-chars';\n\
e5d4f4dc 314 such characters are treated as whitespace when they occur\n\
8489eb67 315 between expressions.")
2fcea188 316 (char, s, table)
8489eb67
RS
317*/
318
319DEFUN ("modify-syntax-entry", Fmodify_syntax_entry, Smodify_syntax_entry, 2, 3,
320 /* I really don't know why this is interactive
321 help-form should at least be made useful whilst reading the second arg
322 */
323 "cSet syntax for character: \nsSet syntax for %s to: ",
324 0 /* See immediately above */)
325 (c, newentry, syntax_table)
326 Lisp_Object c, newentry, syntax_table;
327{
8ea151b2 328 register unsigned char *p;
8489eb67 329 register enum syntaxcode code;
247e20a8 330 int val;
8ea151b2 331 Lisp_Object match;
8489eb67
RS
332
333 CHECK_NUMBER (c, 0);
334 CHECK_STRING (newentry, 1);
8ea151b2 335
265a9e55 336 if (NILP (syntax_table))
8489eb67
RS
337 syntax_table = current_buffer->syntax_table;
338 else
8ea151b2 339 check_syntax_table (syntax_table);
8489eb67
RS
340
341 p = XSTRING (newentry)->data;
342 code = (enum syntaxcode) syntax_spec_code[*p++];
343 if (((int) code & 0377) == 0377)
344 error ("invalid syntax description letter: %c", c);
345
8ea151b2
RS
346 if (code == Sinherit)
347 {
348 SET_RAW_SYNTAX_ENTRY (syntax_table, c, Qnil);
349 return Qnil;
350 }
351
352 if (*p)
d1be9f0f
RS
353 {
354 XSETINT (match, *p++);
355 if (XFASTINT (match) == ' ')
356 match = Qnil;
357 }
358 else
8ea151b2 359 match = Qnil;
8489eb67 360
8ea151b2 361 val = (int) code;
8489eb67
RS
362 while (*p)
363 switch (*p++)
364 {
365 case '1':
247e20a8 366 val |= 1 << 16;
8489eb67
RS
367 break;
368
369 case '2':
247e20a8 370 val |= 1 << 17;
8489eb67
RS
371 break;
372
373 case '3':
247e20a8 374 val |= 1 << 18;
8489eb67
RS
375 break;
376
377 case '4':
247e20a8 378 val |= 1 << 19;
8489eb67
RS
379 break;
380
381 case 'p':
247e20a8 382 val |= 1 << 20;
8489eb67 383 break;
e5d4f4dc
RS
384
385 case 'b':
247e20a8 386 val |= 1 << 21;
e5d4f4dc 387 break;
8489eb67
RS
388 }
389
8ea151b2
RS
390 SET_RAW_SYNTAX_ENTRY (syntax_table, c,
391 Fcons (make_number (val), match));
8489eb67
RS
392
393 return Qnil;
394}
395\f
396/* Dump syntax table to buffer in human-readable format */
397
340f92b5 398static void
8489eb67
RS
399describe_syntax (value)
400 Lisp_Object value;
401{
402 register enum syntaxcode code;
e5d4f4dc 403 char desc, match, start1, start2, end1, end2, prefix, comstyle;
8489eb67 404 char str[2];
8ea151b2 405 Lisp_Object first, match_lisp;
8489eb67
RS
406
407 Findent_to (make_number (16), make_number (1));
408
8ea151b2
RS
409 if (NILP (value))
410 {
411 insert_string ("inherit");
412 return;
413 }
414
415 if (!CONSP (value))
416 {
417 insert_string ("invalid");
418 return;
419 }
420
421 first = XCONS (value)->car;
422 match_lisp = XCONS (value)->cdr;
423
424 if (!INTEGERP (first) || !(NILP (match_lisp) || INTEGERP (match_lisp)))
8489eb67
RS
425 {
426 insert_string ("invalid");
427 return;
428 }
429
8ea151b2
RS
430 code = (enum syntaxcode) (first & 0377);
431 start1 = (XINT (first) >> 16) & 1;
432 start2 = (XINT (first) >> 17) & 1;
433 end1 = (XINT (first) >> 18) & 1;
434 end2 = (XINT (first) >> 19) & 1;
435 prefix = (XINT (first) >> 20) & 1;
436 comstyle = (XINT (first) >> 21) & 1;
8489eb67
RS
437
438 if ((int) code < 0 || (int) code >= (int) Smax)
439 {
440 insert_string ("invalid");
441 return;
442 }
443 desc = syntax_code_spec[(int) code];
444
445 str[0] = desc, str[1] = 0;
446 insert (str, 1);
447
8ea151b2 448 str[0] = !NILP (match_lisp) ? XINT (match_lisp) : ' ';
8489eb67
RS
449 insert (str, 1);
450
8489eb67
RS
451 if (start1)
452 insert ("1", 1);
453 if (start2)
454 insert ("2", 1);
455
456 if (end1)
457 insert ("3", 1);
458 if (end2)
459 insert ("4", 1);
460
461 if (prefix)
462 insert ("p", 1);
e5d4f4dc
RS
463 if (comstyle)
464 insert ("b", 1);
8489eb67
RS
465
466 insert_string ("\twhich means: ");
467
0220c518 468 switch (SWITCH_ENUM_CAST (code))
8489eb67
RS
469 {
470 case Swhitespace:
471 insert_string ("whitespace"); break;
472 case Spunct:
473 insert_string ("punctuation"); break;
474 case Sword:
475 insert_string ("word"); break;
476 case Ssymbol:
477 insert_string ("symbol"); break;
478 case Sopen:
479 insert_string ("open"); break;
480 case Sclose:
481 insert_string ("close"); break;
482 case Squote:
483 insert_string ("quote"); break;
484 case Sstring:
485 insert_string ("string"); break;
486 case Smath:
487 insert_string ("math"); break;
488 case Sescape:
489 insert_string ("escape"); break;
490 case Scharquote:
491 insert_string ("charquote"); break;
492 case Scomment:
493 insert_string ("comment"); break;
494 case Sendcomment:
495 insert_string ("endcomment"); break;
496 default:
497 insert_string ("invalid");
498 return;
499 }
500
8ea151b2 501 if (!NILP (match_lisp))
8489eb67
RS
502 {
503 insert_string (", matches ");
8ea151b2 504 insert_char (XINT (match_lisp));
8489eb67
RS
505 }
506
507 if (start1)
508 insert_string (",\n\t is the first character of a comment-start sequence");
509 if (start2)
510 insert_string (",\n\t is the second character of a comment-start sequence");
511
512 if (end1)
513 insert_string (",\n\t is the first character of a comment-end sequence");
514 if (end2)
515 insert_string (",\n\t is the second character of a comment-end sequence");
e5d4f4dc
RS
516 if (comstyle)
517 insert_string (" (comment style b)");
518
8489eb67
RS
519 if (prefix)
520 insert_string (",\n\t is a prefix character for `backward-prefix-chars'");
521
522 insert_string ("\n");
523}
524
340f92b5 525static Lisp_Object
8489eb67
RS
526describe_syntax_1 (vector)
527 Lisp_Object vector;
528{
529 struct buffer *old = current_buffer;
530 set_buffer_internal (XBUFFER (Vstandard_output));
5588734e 531 describe_vector (vector, Qnil, describe_syntax, 0, Qnil, Qnil);
36cd82fe 532 call0 (intern ("help-mode"));
8489eb67
RS
533 set_buffer_internal (old);
534 return Qnil;
535}
536
537DEFUN ("describe-syntax", Fdescribe_syntax, Sdescribe_syntax, 0, 0, "",
538 "Describe the syntax specifications in the syntax table.\n\
539The descriptions are inserted in a buffer, which is then displayed.")
540 ()
541{
542 internal_with_output_to_temp_buffer
543 ("*Help*", describe_syntax_1, current_buffer->syntax_table);
544
545 return Qnil;
546}
547\f
548/* Return the position across COUNT words from FROM.
549 If that many words cannot be found before the end of the buffer, return 0.
550 COUNT negative means scan backward and stop at word beginning. */
551
552scan_words (from, count)
553 register int from, count;
554{
555 register int beg = BEGV;
556 register int end = ZV;
557 register int code;
8ea151b2 558 int charcode;
8489eb67
RS
559
560 immediate_quit = 1;
561 QUIT;
562
563 while (count > 0)
564 {
565 while (1)
566 {
567 if (from == end)
568 {
569 immediate_quit = 0;
570 return 0;
571 }
8ea151b2
RS
572 charcode = FETCH_CHAR (from);
573 code = SYNTAX (charcode);
8489eb67
RS
574 if (words_include_escapes
575 && (code == Sescape || code == Scharquote))
576 break;
577 if (code == Sword)
578 break;
579 from++;
580 }
581 while (1)
582 {
583 if (from == end) break;
8ea151b2
RS
584 charcode = FETCH_CHAR (from);
585 code = SYNTAX (charcode);
8489eb67
RS
586 if (!(words_include_escapes
587 && (code == Sescape || code == Scharquote)))
588 if (code != Sword)
589 break;
590 from++;
591 }
592 count--;
593 }
594 while (count < 0)
595 {
596 while (1)
597 {
598 if (from == beg)
599 {
600 immediate_quit = 0;
601 return 0;
602 }
8ea151b2
RS
603 charcode = FETCH_CHAR (from - 1);
604 code = SYNTAX (charcode);
8489eb67
RS
605 if (words_include_escapes
606 && (code == Sescape || code == Scharquote))
607 break;
608 if (code == Sword)
609 break;
610 from--;
611 }
612 while (1)
613 {
614 if (from == beg) break;
8ea151b2
RS
615 charcode = FETCH_CHAR (from - 1);
616 code = SYNTAX (charcode);
8489eb67
RS
617 if (!(words_include_escapes
618 && (code == Sescape || code == Scharquote)))
619 if (code != Sword)
620 break;
621 from--;
622 }
623 count++;
624 }
625
626 immediate_quit = 0;
627
628 return from;
629}
630
631DEFUN ("forward-word", Fforward_word, Sforward_word, 1, 1, "p",
632 "Move point forward ARG words (backward if ARG is negative).\n\
633Normally returns t.\n\
634If an edge of the buffer is reached, point is left there\n\
635and nil is returned.")
636 (count)
637 Lisp_Object count;
638{
639 int val;
640 CHECK_NUMBER (count, 0);
641
6ec8bbd2 642 if (!(val = scan_words (PT, XINT (count))))
8489eb67
RS
643 {
644 SET_PT (XINT (count) > 0 ? ZV : BEGV);
645 return Qnil;
646 }
647 SET_PT (val);
648 return Qt;
649}
650\f
b3cfe0c8
RS
651DEFUN ("forward-comment", Fforward_comment, Sforward_comment, 1, 1, 0,
652 "Move forward across up to N comments. If N is negative, move backward.\n\
b3cfe0c8 653Stop scanning if we find something other than a comment or whitespace.\n\
c81a3712 654Set point to where scanning stops.\n\
b3cfe0c8
RS
655If N comments are found as expected, with nothing except whitespace\n\
656between them, return t; otherwise return nil.")
657 (count)
840f481c 658 Lisp_Object count;
b3cfe0c8
RS
659{
660 register int from;
661 register int stop;
8ea151b2 662 register int c, c1;
b3cfe0c8
RS
663 register enum syntaxcode code;
664 int comstyle = 0; /* style of comment encountered */
be720845 665 int found;
840f481c
RS
666 int count1;
667
668 CHECK_NUMBER (count, 0);
669 count1 = XINT (count);
b3cfe0c8
RS
670
671 immediate_quit = 1;
672 QUIT;
673
674 from = PT;
675
840f481c 676 while (count1 > 0)
b3cfe0c8
RS
677 {
678 stop = ZV;
04882296 679 do
b3cfe0c8 680 {
04882296
KH
681 if (from == stop)
682 {
683 SET_PT (from);
b7e6e612 684 immediate_quit = 0;
04882296
KH
685 return Qnil;
686 }
b3cfe0c8
RS
687 c = FETCH_CHAR (from);
688 code = SYNTAX (c);
689 from++;
690 comstyle = 0;
691 if (from < stop && SYNTAX_COMSTART_FIRST (c)
8ea151b2
RS
692 && (c1 = FETCH_CHAR (from),
693 SYNTAX_COMSTART_SECOND (c1)))
b3cfe0c8 694 {
7fc8191e
RS
695 /* We have encountered a comment start sequence and we
696 are ignoring all text inside comments. We must record
b3cfe0c8
RS
697 the comment style this sequence begins so that later,
698 only a comment end of the same style actually ends
7fc8191e 699 the comment section. */
b3cfe0c8 700 code = Scomment;
8ea151b2 701 comstyle = SYNTAX_COMMENT_STYLE (c1);
b3cfe0c8
RS
702 from++;
703 }
04882296
KH
704 }
705 while (code == Swhitespace || code == Sendcomment);
706 if (code != Scomment)
707 {
708 immediate_quit = 0;
709 SET_PT (from - 1);
710 return Qnil;
711 }
712 /* We're at the start of a comment. */
713 while (1)
714 {
715 if (from == stop)
b3cfe0c8
RS
716 {
717 immediate_quit = 0;
04882296 718 SET_PT (from);
b3cfe0c8
RS
719 return Qnil;
720 }
04882296 721 c = FETCH_CHAR (from);
2eb1d6a2 722 from++;
04882296
KH
723 if (SYNTAX (c) == Sendcomment
724 && SYNTAX_COMMENT_STYLE (c) == comstyle)
725 /* we have encountered a comment end of the same style
726 as the comment sequence which began this comment
727 section */
728 break;
04882296 729 if (from < stop && SYNTAX_COMEND_FIRST (c)
8ea151b2
RS
730 && (c1 = FETCH_CHAR (from),
731 SYNTAX_COMEND_SECOND (c1))
04882296
KH
732 && SYNTAX_COMMENT_STYLE (c) == comstyle)
733 /* we have encountered a comment end of the same style
734 as the comment sequence which began this comment
735 section */
736 { from++; break; }
b3cfe0c8 737 }
04882296 738 /* We have skipped one comment. */
840f481c 739 count1--;
b3cfe0c8
RS
740 }
741
840f481c 742 while (count1 < 0)
b3cfe0c8
RS
743 {
744 stop = BEGV;
745 while (from > stop)
746 {
747 int quoted;
748
749 from--;
750 quoted = char_quoted (from);
751 if (quoted)
752 from--;
753 c = FETCH_CHAR (from);
754 code = SYNTAX (c);
755 comstyle = 0;
7fc8191e
RS
756 if (code == Sendcomment)
757 comstyle = SYNTAX_COMMENT_STYLE (c);
b3cfe0c8 758 if (from > stop && SYNTAX_COMEND_SECOND (c)
8ea151b2
RS
759 && (c1 = FETCH_CHAR (from - 1),
760 SYNTAX_COMEND_FIRST (c1))
b3cfe0c8
RS
761 && !char_quoted (from - 1))
762 {
7fc8191e 763 /* We must record the comment style encountered so that
b3cfe0c8 764 later, we can match only the proper comment begin
7fc8191e 765 sequence of the same style. */
b3cfe0c8 766 code = Sendcomment;
8ea151b2 767 comstyle = SYNTAX_COMMENT_STYLE (c1);
b3cfe0c8
RS
768 from--;
769 }
770
771 if (code == Sendcomment && !quoted)
772 {
8f9dc2ed 773#if 0
b3cfe0c8
RS
774 if (code != SYNTAX (c))
775 /* For a two-char comment ender, we can assume
776 it does end a comment. So scan back in a simple way. */
777 {
778 if (from != stop) from--;
779 while (1)
780 {
8ea151b2
RS
781 if ((c = FETCH_CHAR (from),
782 SYNTAX (c) == Scomment)
b3cfe0c8
RS
783 && SYNTAX_COMMENT_STYLE (c) == comstyle)
784 break;
785 if (from == stop)
786 {
787 immediate_quit = 0;
c81a3712 788 SET_PT (from);
b3cfe0c8
RS
789 return Qnil;
790 }
791 from--;
792 if (SYNTAX_COMSTART_SECOND (c)
8ea151b2
RS
793 && (c1 = FETCH_CHAR (from),
794 SYNTAX_COMSTART_FIRST (c1))
b3cfe0c8
RS
795 && SYNTAX_COMMENT_STYLE (c) == comstyle
796 && !char_quoted (from))
797 break;
798 }
799 break;
800 }
8f9dc2ed 801#endif /* 0 */
b3cfe0c8
RS
802
803 /* Look back, counting the parity of string-quotes,
804 and recording the comment-starters seen.
805 When we reach a safe place, assume that's not in a string;
806 then step the main scan to the earliest comment-starter seen
807 an even number of string quotes away from the safe place.
808
809 OFROM[I] is position of the earliest comment-starter seen
810 which is I+2X quotes from the comment-end.
811 PARITY is current parity of quotes from the comment end. */
812 {
813 int parity = 0;
814 char my_stringend = 0;
815 int string_lossage = 0;
816 int comment_end = from;
817 int comstart_pos = 0;
818 int comstart_parity = 0;
4841063f 819 int scanstart = from - 1;
b3cfe0c8
RS
820
821 /* At beginning of range to scan, we're outside of strings;
822 that determines quote parity to the comment-end. */
823 while (from != stop)
824 {
825 /* Move back and examine a character. */
826 from--;
827
828 c = FETCH_CHAR (from);
829 code = SYNTAX (c);
830
831 /* If this char is the second of a 2-char comment sequence,
832 back up and give the pair the appropriate syntax. */
833 if (from > stop && SYNTAX_COMEND_SECOND (c)
834 && SYNTAX_COMEND_FIRST (FETCH_CHAR (from - 1)))
835 {
836 code = Sendcomment;
837 from--;
4841063f 838 c = FETCH_CHAR (from);
b3cfe0c8
RS
839 }
840
4841063f
RS
841 /* If this char starts a 2-char comment start sequence,
842 treat it like a 1-char comment starter. */
843 if (from < scanstart && SYNTAX_COMSTART_FIRST (c)
844 && SYNTAX_COMSTART_SECOND (FETCH_CHAR (from + 1))
845 && comstyle == SYNTAX_COMMENT_STYLE (FETCH_CHAR (from + 1)))
846 code = Scomment;
b3cfe0c8
RS
847
848 /* Ignore escaped characters. */
849 if (char_quoted (from))
850 continue;
851
852 /* Track parity of quotes. */
853 if (code == Sstring)
854 {
855 parity ^= 1;
856 if (my_stringend == 0)
857 my_stringend = c;
858 /* If we have two kinds of string delimiters.
859 There's no way to grok this scanning backwards. */
860 else if (my_stringend != c)
861 string_lossage = 1;
862 }
863
864 /* Record comment-starters according to that
865 quote-parity to the comment-end. */
866 if (code == Scomment)
867 {
868 comstart_parity = parity;
869 comstart_pos = from;
870 }
871
872 /* If we find another earlier comment-ender,
eb8c3be9 873 any comment-starts earlier than that don't count
b3cfe0c8
RS
874 (because they go with the earlier comment-ender). */
875 if (code == Sendcomment
876 && SYNTAX_COMMENT_STYLE (FETCH_CHAR (from)) == comstyle)
877 break;
878
879 /* Assume a defun-start point is outside of strings. */
880 if (code == Sopen
881 && (from == stop || FETCH_CHAR (from - 1) == '\n'))
882 break;
883 }
884
885 if (comstart_pos == 0)
886 from = comment_end;
887 /* If the earliest comment starter
888 is followed by uniform paired string quotes or none,
889 we know it can't be inside a string
890 since if it were then the comment ender would be inside one.
891 So it does start a comment. Skip back to it. */
892 else if (comstart_parity == 0 && !string_lossage)
893 from = comstart_pos;
894 else
895 {
896 /* We had two kinds of string delimiters mixed up
897 together. Decode this going forwards.
898 Scan fwd from the previous comment ender
899 to the one in question; this records where we
900 last passed a comment starter. */
901 struct lisp_parse_state state;
902 scan_sexps_forward (&state, find_defun_start (comment_end),
340f92b5 903 comment_end - 1, -10000, 0, Qnil, 0);
b3cfe0c8
RS
904 if (state.incomment)
905 from = state.comstart;
906 else
907 /* We can't grok this as a comment; scan it normally. */
908 from = comment_end;
909 }
910 }
7fc8191e
RS
911 /* We have skipped one comment. */
912 break;
b3cfe0c8 913 }
c81a3712 914 else if ((code != Swhitespace && code != Scomment) || quoted)
b3cfe0c8
RS
915 {
916 immediate_quit = 0;
c81a3712 917 SET_PT (from + 1);
b3cfe0c8
RS
918 return Qnil;
919 }
920 }
921
840f481c 922 count1++;
b3cfe0c8
RS
923 }
924
925 SET_PT (from);
926 immediate_quit = 0;
927 return Qt;
928}
929\f
8489eb67
RS
930int parse_sexp_ignore_comments;
931
932Lisp_Object
933scan_lists (from, count, depth, sexpflag)
934 register int from;
935 int count, depth, sexpflag;
936{
937 Lisp_Object val;
938 register int stop;
939 register int c;
ee384542 940 unsigned char stringterm;
8489eb67
RS
941 int quoted;
942 int mathexit = 0;
943 register enum syntaxcode code;
944 int min_depth = depth; /* Err out if depth gets less than this. */
e5d4f4dc 945 int comstyle = 0; /* style of comment encountered */
8489eb67
RS
946
947 if (depth > 0) min_depth = 0;
948
949 immediate_quit = 1;
950 QUIT;
951
952 while (count > 0)
953 {
954 stop = ZV;
955 while (from < stop)
956 {
957 c = FETCH_CHAR (from);
e5d4f4dc 958 code = SYNTAX (c);
8489eb67
RS
959 from++;
960 if (from < stop && SYNTAX_COMSTART_FIRST (c)
961 && SYNTAX_COMSTART_SECOND (FETCH_CHAR (from))
962 && parse_sexp_ignore_comments)
e5d4f4dc
RS
963 {
964 /* we have encountered a comment start sequence and we
965 are ignoring all text inside comments. we must record
966 the comment style this sequence begins so that later,
967 only a comment end of the same style actually ends
968 the comment section */
969 code = Scomment;
970 comstyle = SYNTAX_COMMENT_STYLE (FETCH_CHAR (from));
971 from++;
972 }
973
8489eb67
RS
974 if (SYNTAX_PREFIX (c))
975 continue;
976
0220c518 977 switch (SWITCH_ENUM_CAST (code))
8489eb67
RS
978 {
979 case Sescape:
980 case Scharquote:
981 if (from == stop) goto lose;
982 from++;
983 /* treat following character as a word constituent */
984 case Sword:
985 case Ssymbol:
986 if (depth || !sexpflag) break;
987 /* This word counts as a sexp; return at end of it. */
988 while (from < stop)
989 {
0220c518 990 switch (SWITCH_ENUM_CAST (SYNTAX (FETCH_CHAR (from))))
8489eb67
RS
991 {
992 case Scharquote:
993 case Sescape:
994 from++;
995 if (from == stop) goto lose;
996 break;
997 case Sword:
998 case Ssymbol:
999 case Squote:
1000 break;
1001 default:
1002 goto done;
1003 }
1004 from++;
1005 }
1006 goto done;
1007
1008 case Scomment:
1009 if (!parse_sexp_ignore_comments) break;
1010 while (1)
1011 {
c01f7ec0
RS
1012 if (from == stop)
1013 {
1014 if (depth == 0)
1015 goto done;
1016 goto lose;
1017 }
e5d4f4dc
RS
1018 c = FETCH_CHAR (from);
1019 if (SYNTAX (c) == Sendcomment
1020 && SYNTAX_COMMENT_STYLE (c) == comstyle)
1021 /* we have encountered a comment end of the same style
1022 as the comment sequence which began this comment
1023 section */
8489eb67
RS
1024 break;
1025 from++;
1026 if (from < stop && SYNTAX_COMEND_FIRST (c)
e5d4f4dc
RS
1027 && SYNTAX_COMEND_SECOND (FETCH_CHAR (from))
1028 && SYNTAX_COMMENT_STYLE (c) == comstyle)
1029 /* we have encountered a comment end of the same style
1030 as the comment sequence which began this comment
1031 section */
8489eb67
RS
1032 { from++; break; }
1033 }
1034 break;
1035
1036 case Smath:
1037 if (!sexpflag)
1038 break;
1039 if (from != stop && c == FETCH_CHAR (from))
1040 from++;
1041 if (mathexit)
1042 {
1043 mathexit = 0;
1044 goto close1;
1045 }
1046 mathexit = 1;
1047
1048 case Sopen:
1049 if (!++depth) goto done;
1050 break;
1051
1052 case Sclose:
1053 close1:
1054 if (!--depth) goto done;
1055 if (depth < min_depth)
1056 error ("Containing expression ends prematurely");
1057 break;
1058
1059 case Sstring:
1060 stringterm = FETCH_CHAR (from - 1);
1061 while (1)
1062 {
1063 if (from >= stop) goto lose;
1064 if (FETCH_CHAR (from) == stringterm) break;
0220c518 1065 switch (SWITCH_ENUM_CAST (SYNTAX (FETCH_CHAR (from))))
8489eb67
RS
1066 {
1067 case Scharquote:
1068 case Sescape:
1069 from++;
1070 }
1071 from++;
1072 }
1073 from++;
1074 if (!depth && sexpflag) goto done;
1075 break;
1076 }
1077 }
1078
1079 /* Reached end of buffer. Error if within object, return nil if between */
1080 if (depth) goto lose;
1081
1082 immediate_quit = 0;
1083 return Qnil;
1084
1085 /* End of object reached */
1086 done:
1087 count--;
1088 }
1089
1090 while (count < 0)
1091 {
1092 stop = BEGV;
1093 while (from > stop)
1094 {
1095 from--;
1096 if (quoted = char_quoted (from))
1097 from--;
1098 c = FETCH_CHAR (from);
1099 code = SYNTAX (c);
7fc8191e
RS
1100 comstyle = 0;
1101 if (code == Sendcomment)
1102 comstyle = SYNTAX_COMMENT_STYLE (c);
8489eb67
RS
1103 if (from > stop && SYNTAX_COMEND_SECOND (c)
1104 && SYNTAX_COMEND_FIRST (FETCH_CHAR (from - 1))
1105 && !char_quoted (from - 1)
1106 && parse_sexp_ignore_comments)
e5d4f4dc
RS
1107 {
1108 /* we must record the comment style encountered so that
1109 later, we can match only the proper comment begin
1110 sequence of the same style */
1111 code = Sendcomment;
1112 comstyle = SYNTAX_COMMENT_STYLE (FETCH_CHAR (from - 1));
1113 from--;
1114 }
1115
8489eb67
RS
1116 if (SYNTAX_PREFIX (c))
1117 continue;
1118
0220c518 1119 switch (SWITCH_ENUM_CAST (quoted ? Sword : code))
8489eb67
RS
1120 {
1121 case Sword:
1122 case Ssymbol:
1123 if (depth || !sexpflag) break;
1124 /* This word counts as a sexp; count object finished after passing it. */
1125 while (from > stop)
1126 {
1127 quoted = char_quoted (from - 1);
1128 if (quoted)
1129 from--;
e5d4f4dc
RS
1130 if (! (quoted || SYNTAX (FETCH_CHAR (from - 1)) == Sword
1131 || SYNTAX (FETCH_CHAR (from - 1)) == Ssymbol
1132 || SYNTAX (FETCH_CHAR (from - 1)) == Squote))
8489eb67
RS
1133 goto done2;
1134 from--;
1135 }
1136 goto done2;
1137
1138 case Smath:
1139 if (!sexpflag)
1140 break;
1141 if (from != stop && c == FETCH_CHAR (from - 1))
1142 from--;
1143 if (mathexit)
1144 {
1145 mathexit = 0;
1146 goto open2;
1147 }
1148 mathexit = 1;
1149
1150 case Sclose:
1151 if (!++depth) goto done2;
1152 break;
1153
1154 case Sopen:
1155 open2:
1156 if (!--depth) goto done2;
1157 if (depth < min_depth)
1158 error ("Containing expression ends prematurely");
1159 break;
1160
1161 case Sendcomment:
1162 if (!parse_sexp_ignore_comments)
1163 break;
8f9dc2ed 1164#if 0
37bef230
RS
1165 if (code != SYNTAX (c))
1166 /* For a two-char comment ender, we can assume
1167 it does end a comment. So scan back in a simple way. */
1168 {
1169 if (from != stop) from--;
1170 while (1)
1171 {
1172 if (SYNTAX (c = FETCH_CHAR (from)) == Scomment
1173 && SYNTAX_COMMENT_STYLE (c) == comstyle)
1174 break;
c01f7ec0
RS
1175 if (from == stop)
1176 {
1177 if (depth == 0)
1178 goto done2;
1179 goto lose;
1180 }
37bef230
RS
1181 from--;
1182 if (SYNTAX_COMSTART_SECOND (c)
1183 && SYNTAX_COMSTART_FIRST (FETCH_CHAR (from))
1184 && SYNTAX_COMMENT_STYLE (c) == comstyle
1185 && !char_quoted (from))
1186 break;
1187 }
1188 break;
1189 }
8f9dc2ed 1190#endif /* 0 */
37bef230 1191
8489eb67
RS
1192 /* Look back, counting the parity of string-quotes,
1193 and recording the comment-starters seen.
1194 When we reach a safe place, assume that's not in a string;
1195 then step the main scan to the earliest comment-starter seen
1196 an even number of string quotes away from the safe place.
1197
1198 OFROM[I] is position of the earliest comment-starter seen
1199 which is I+2X quotes from the comment-end.
1200 PARITY is current parity of quotes from the comment end. */
1201 {
8489eb67 1202 int parity = 0;
e5d4f4dc
RS
1203 char my_stringend = 0;
1204 int string_lossage = 0;
1205 int comment_end = from;
37bef230
RS
1206 int comstart_pos = 0;
1207 int comstart_parity = 0;
4841063f 1208 int scanstart = from - 1;
8489eb67
RS
1209
1210 /* At beginning of range to scan, we're outside of strings;
1211 that determines quote parity to the comment-end. */
1212 while (from != stop)
1213 {
1214 /* Move back and examine a character. */
1215 from--;
1216
1217 c = FETCH_CHAR (from);
1218 code = SYNTAX (c);
1219
1220 /* If this char is the second of a 2-char comment sequence,
1221 back up and give the pair the appropriate syntax. */
1222 if (from > stop && SYNTAX_COMEND_SECOND (c)
1223 && SYNTAX_COMEND_FIRST (FETCH_CHAR (from - 1)))
e5d4f4dc
RS
1224 {
1225 code = Sendcomment;
1226 from--;
4841063f 1227 c = FETCH_CHAR (from);
e5d4f4dc
RS
1228 }
1229
4841063f
RS
1230 /* If this char starts a 2-char comment start sequence,
1231 treat it like a 1-char comment starter. */
1232 if (from < scanstart && SYNTAX_COMSTART_FIRST (c)
1233 && SYNTAX_COMSTART_SECOND (FETCH_CHAR (from + 1))
1234 && comstyle == SYNTAX_COMMENT_STYLE (FETCH_CHAR (from + 1)))
1235 code = Scomment;
8489eb67
RS
1236
1237 /* Ignore escaped characters. */
1238 if (char_quoted (from))
1239 continue;
1240
37bef230 1241 /* Track parity of quotes. */
8489eb67 1242 if (code == Sstring)
e5d4f4dc
RS
1243 {
1244 parity ^= 1;
1245 if (my_stringend == 0)
1246 my_stringend = c;
37bef230 1247 /* If we have two kinds of string delimiters.
e5d4f4dc
RS
1248 There's no way to grok this scanning backwards. */
1249 else if (my_stringend != c)
1250 string_lossage = 1;
1251 }
8489eb67
RS
1252
1253 /* Record comment-starters according to that
1254 quote-parity to the comment-end. */
1255 if (code == Scomment)
37bef230
RS
1256 {
1257 comstart_parity = parity;
1258 comstart_pos = from;
1259 }
8489eb67 1260
37bef230 1261 /* If we find another earlier comment-ender,
eb8c3be9 1262 any comment-starts earlier than that don't count
37bef230 1263 (because they go with the earlier comment-ender). */
e5d4f4dc
RS
1264 if (code == Sendcomment
1265 && SYNTAX_COMMENT_STYLE (FETCH_CHAR (from)) == comstyle)
8489eb67 1266 break;
37bef230
RS
1267
1268 /* Assume a defun-start point is outside of strings. */
1269 if (code == Sopen
1270 && (from == stop || FETCH_CHAR (from - 1) == '\n'))
1271 break;
8489eb67 1272 }
37bef230
RS
1273
1274 if (comstart_pos == 0)
1275 from = comment_end;
1276 /* If the earliest comment starter
1277 is followed by uniform paired string quotes or none,
1278 we know it can't be inside a string
1279 since if it were then the comment ender would be inside one.
1280 So it does start a comment. Skip back to it. */
1281 else if (comstart_parity == 0 && !string_lossage)
1282 from = comstart_pos;
1283 else
e5d4f4dc
RS
1284 {
1285 /* We had two kinds of string delimiters mixed up
1286 together. Decode this going forwards.
1287 Scan fwd from the previous comment ender
1288 to the one in question; this records where we
1289 last passed a comment starter. */
1290 struct lisp_parse_state state;
37bef230 1291 scan_sexps_forward (&state, find_defun_start (comment_end),
340f92b5 1292 comment_end - 1, -10000, 0, Qnil, 0);
e5d4f4dc
RS
1293 if (state.incomment)
1294 from = state.comstart;
1295 else
1296 /* We can't grok this as a comment; scan it normally. */
1297 from = comment_end;
1298 }
8489eb67
RS
1299 }
1300 break;
1301
1302 case Sstring:
1303 stringterm = FETCH_CHAR (from);
1304 while (1)
1305 {
1306 if (from == stop) goto lose;
1307 if (!char_quoted (from - 1)
1308 && stringterm == FETCH_CHAR (from - 1))
1309 break;
1310 from--;
1311 }
1312 from--;
1313 if (!depth && sexpflag) goto done2;
1314 break;
1315 }
1316 }
1317
1318 /* Reached start of buffer. Error if within object, return nil if between */
1319 if (depth) goto lose;
1320
1321 immediate_quit = 0;
1322 return Qnil;
1323
1324 done2:
1325 count++;
1326 }
1327
1328
1329 immediate_quit = 0;
1e142fb7 1330 XSETFASTINT (val, from);
8489eb67
RS
1331 return val;
1332
1333 lose:
1334 error ("Unbalanced parentheses");
1335 /* NOTREACHED */
1336}
1337
340f92b5 1338static int
8489eb67
RS
1339char_quoted (pos)
1340 register int pos;
1341{
1342 register enum syntaxcode code;
1343 register int beg = BEGV;
1344 register int quoted = 0;
1345
1346 while (pos > beg
1347 && ((code = SYNTAX (FETCH_CHAR (pos - 1))) == Scharquote
1348 || code == Sescape))
1349 pos--, quoted = !quoted;
1350 return quoted;
1351}
1352
1353DEFUN ("scan-lists", Fscan_lists, Sscan_lists, 3, 3, 0,
1354 "Scan from character number FROM by COUNT lists.\n\
1355Returns the character number of the position thus found.\n\
1356\n\
1357If DEPTH is nonzero, paren depth begins counting from that value,\n\
1358only places where the depth in parentheses becomes zero\n\
1359are candidates for stopping; COUNT such places are counted.\n\
1360Thus, a positive value for DEPTH means go out levels.\n\
1361\n\
1362Comments are ignored if `parse-sexp-ignore-comments' is non-nil.\n\
1363\n\
1364If the beginning or end of (the accessible part of) the buffer is reached\n\
1365and the depth is wrong, an error is signaled.\n\
1366If the depth is right but the count is not used up, nil is returned.")
1367 (from, count, depth)
1368 Lisp_Object from, count, depth;
1369{
1370 CHECK_NUMBER (from, 0);
1371 CHECK_NUMBER (count, 1);
1372 CHECK_NUMBER (depth, 2);
1373
1374 return scan_lists (XINT (from), XINT (count), XINT (depth), 0);
1375}
1376
1377DEFUN ("scan-sexps", Fscan_sexps, Sscan_sexps, 2, 2, 0,
1378 "Scan from character number FROM by COUNT balanced expressions.\n\
1379If COUNT is negative, scan backwards.\n\
1380Returns the character number of the position thus found.\n\
1381\n\
1382Comments are ignored if `parse-sexp-ignore-comments' is non-nil.\n\
1383\n\
1384If the beginning or end of (the accessible part of) the buffer is reached\n\
1385in the middle of a parenthetical grouping, an error is signaled.\n\
1386If the beginning or end is reached between groupings\n\
1387but before count is used up, nil is returned.")
1388 (from, count)
1389 Lisp_Object from, count;
1390{
1391 CHECK_NUMBER (from, 0);
1392 CHECK_NUMBER (count, 1);
1393
1394 return scan_lists (XINT (from), XINT (count), 0, 1);
1395}
1396
1397DEFUN ("backward-prefix-chars", Fbackward_prefix_chars, Sbackward_prefix_chars,
1398 0, 0, 0,
1399 "Move point backward over any number of chars with prefix syntax.\n\
1400This includes chars with \"quote\" or \"prefix\" syntax (' or p).")
1401 ()
1402{
1403 int beg = BEGV;
6ec8bbd2 1404 int pos = PT;
8489eb67
RS
1405
1406 while (pos > beg && !char_quoted (pos - 1)
1407 && (SYNTAX (FETCH_CHAR (pos - 1)) == Squote
1408 || SYNTAX_PREFIX (FETCH_CHAR (pos - 1))))
1409 pos--;
1410
1411 SET_PT (pos);
1412
1413 return Qnil;
1414}
1415\f
8489eb67 1416/* Parse forward from FROM to END,
e5d4f4dc
RS
1417 assuming that FROM has state OLDSTATE (nil means FROM is start of function),
1418 and return a description of the state of the parse at END.
c81a3712
RS
1419 If STOPBEFORE is nonzero, stop at the start of an atom.
1420 If COMMENTSTOP is nonzero, stop at the start of a comment. */
8489eb67 1421
340f92b5 1422static void
c81a3712
RS
1423scan_sexps_forward (stateptr, from, end, targetdepth,
1424 stopbefore, oldstate, commentstop)
e5d4f4dc 1425 struct lisp_parse_state *stateptr;
8489eb67
RS
1426 register int from;
1427 int end, targetdepth, stopbefore;
1428 Lisp_Object oldstate;
c81a3712 1429 int commentstop;
8489eb67
RS
1430{
1431 struct lisp_parse_state state;
1432
1433 register enum syntaxcode code;
1434 struct level { int last, prev; };
1435 struct level levelstart[100];
1436 register struct level *curlevel = levelstart;
1437 struct level *endlevel = levelstart + 100;
1438 char prev;
1439 register int depth; /* Paren depth of current scanning location.
1440 level - levelstart equals this except
1441 when the depth becomes negative. */
1442 int mindepth; /* Lowest DEPTH value seen. */
1443 int start_quoted = 0; /* Nonzero means starting after a char quote */
1444 Lisp_Object tem;
1445
1446 immediate_quit = 1;
1447 QUIT;
1448
265a9e55 1449 if (NILP (oldstate))
8489eb67
RS
1450 {
1451 depth = 0;
1452 state.instring = -1;
1453 state.incomment = 0;
e5d4f4dc 1454 state.comstyle = 0; /* comment style a by default */
8489eb67
RS
1455 }
1456 else
1457 {
1458 tem = Fcar (oldstate);
265a9e55 1459 if (!NILP (tem))
8489eb67
RS
1460 depth = XINT (tem);
1461 else
1462 depth = 0;
1463
1464 oldstate = Fcdr (oldstate);
1465 oldstate = Fcdr (oldstate);
1466 oldstate = Fcdr (oldstate);
1467 tem = Fcar (oldstate);
265a9e55 1468 state.instring = !NILP (tem) ? XINT (tem) : -1;
8489eb67
RS
1469
1470 oldstate = Fcdr (oldstate);
1471 tem = Fcar (oldstate);
265a9e55 1472 state.incomment = !NILP (tem);
8489eb67
RS
1473
1474 oldstate = Fcdr (oldstate);
1475 tem = Fcar (oldstate);
265a9e55 1476 start_quoted = !NILP (tem);
e5d4f4dc
RS
1477
1478 /* if the eight element of the list is nil, we are in comment
1479 style a. if it is non-nil, we are in comment style b */
1480 oldstate = Fcdr (oldstate);
1481 oldstate = Fcdr (oldstate);
e5d4f4dc
RS
1482 tem = Fcar (oldstate);
1483 state.comstyle = !NILP (tem);
8489eb67
RS
1484 }
1485 state.quoted = 0;
1486 mindepth = depth;
1487
1488 curlevel->prev = -1;
1489 curlevel->last = -1;
1490
1491 /* Enter the loop at a place appropriate for initial state. */
1492
1493 if (state.incomment) goto startincomment;
1494 if (state.instring >= 0)
1495 {
1496 if (start_quoted) goto startquotedinstring;
1497 goto startinstring;
1498 }
1499 if (start_quoted) goto startquoted;
1500
1501 while (from < end)
1502 {
e5d4f4dc 1503 code = SYNTAX (FETCH_CHAR (from));
8489eb67 1504 from++;
8f9dc2ed
RS
1505 if (code == Scomment)
1506 state.comstart = from-1;
1507
1508 else if (from < end && SYNTAX_COMSTART_FIRST (FETCH_CHAR (from - 1))
1509 && SYNTAX_COMSTART_SECOND (FETCH_CHAR (from)))
e5d4f4dc
RS
1510 {
1511 /* Record the comment style we have entered so that only
1512 the comment-end sequence of the same style actually
1513 terminates the comment section. */
1514 code = Scomment;
1515 state.comstyle = SYNTAX_COMMENT_STYLE (FETCH_CHAR (from));
8f9dc2ed 1516 state.comstart = from-1;
e5d4f4dc
RS
1517 from++;
1518 }
1519
8489eb67
RS
1520 if (SYNTAX_PREFIX (FETCH_CHAR (from - 1)))
1521 continue;
0220c518 1522 switch (SWITCH_ENUM_CAST (code))
8489eb67
RS
1523 {
1524 case Sescape:
1525 case Scharquote:
1526 if (stopbefore) goto stop; /* this arg means stop at sexp start */
1527 curlevel->last = from - 1;
1528 startquoted:
1529 if (from == end) goto endquoted;
1530 from++;
1531 goto symstarted;
1532 /* treat following character as a word constituent */
1533 case Sword:
1534 case Ssymbol:
1535 if (stopbefore) goto stop; /* this arg means stop at sexp start */
1536 curlevel->last = from - 1;
1537 symstarted:
1538 while (from < end)
1539 {
0220c518 1540 switch (SWITCH_ENUM_CAST (SYNTAX (FETCH_CHAR (from))))
8489eb67
RS
1541 {
1542 case Scharquote:
1543 case Sescape:
1544 from++;
1545 if (from == end) goto endquoted;
1546 break;
1547 case Sword:
1548 case Ssymbol:
1549 case Squote:
1550 break;
1551 default:
1552 goto symdone;
1553 }
1554 from++;
1555 }
1556 symdone:
1557 curlevel->prev = curlevel->last;
1558 break;
1559
5a28e48c
RS
1560 startincomment:
1561 if (commentstop)
1562 goto done;
1563 if (from != BEGV)
1564 {
1565 /* Enter the loop in the middle so that we find
1566 a 2-char comment ender if we start in the middle of it. */
1567 prev = FETCH_CHAR (from - 1);
1568 goto startincomment_1;
1569 }
1570 /* At beginning of buffer, enter the loop the ordinary way. */
1571
8489eb67
RS
1572 case Scomment:
1573 state.incomment = 1;
c81a3712
RS
1574 if (commentstop)
1575 goto done;
8489eb67
RS
1576 while (1)
1577 {
1578 if (from == end) goto done;
e5d4f4dc
RS
1579 prev = FETCH_CHAR (from);
1580 if (SYNTAX (prev) == Sendcomment
1581 && SYNTAX_COMMENT_STYLE (prev) == state.comstyle)
1582 /* Only terminate the comment section if the endcomment
1583 of the same style as the start sequence has been
1584 encountered. */
8489eb67
RS
1585 break;
1586 from++;
5a28e48c 1587 startincomment_1:
8489eb67 1588 if (from < end && SYNTAX_COMEND_FIRST (prev)
e5d4f4dc
RS
1589 && SYNTAX_COMEND_SECOND (FETCH_CHAR (from))
1590 && SYNTAX_COMMENT_STYLE (prev) == state.comstyle)
1591 /* Only terminate the comment section if the end-comment
1592 sequence of the same style as the start sequence has
1593 been encountered. */
8489eb67
RS
1594 { from++; break; }
1595 }
1596 state.incomment = 0;
e5d4f4dc 1597 state.comstyle = 0; /* reset the comment style */
8489eb67
RS
1598 break;
1599
1600 case Sopen:
1601 if (stopbefore) goto stop; /* this arg means stop at sexp start */
1602 depth++;
1603 /* curlevel++->last ran into compiler bug on Apollo */
1604 curlevel->last = from - 1;
1605 if (++curlevel == endlevel)
1606 error ("Nesting too deep for parser");
1607 curlevel->prev = -1;
1608 curlevel->last = -1;
30844415 1609 if (targetdepth == depth) goto done;
8489eb67
RS
1610 break;
1611
1612 case Sclose:
1613 depth--;
1614 if (depth < mindepth)
1615 mindepth = depth;
1616 if (curlevel != levelstart)
1617 curlevel--;
1618 curlevel->prev = curlevel->last;
30844415 1619 if (targetdepth == depth) goto done;
8489eb67
RS
1620 break;
1621
1622 case Sstring:
1623 if (stopbefore) goto stop; /* this arg means stop at sexp start */
1624 curlevel->last = from - 1;
1625 state.instring = FETCH_CHAR (from - 1);
1626 startinstring:
1627 while (1)
1628 {
1629 if (from >= end) goto done;
1630 if (FETCH_CHAR (from) == state.instring) break;
0220c518 1631 switch (SWITCH_ENUM_CAST (SYNTAX (FETCH_CHAR (from))))
8489eb67
RS
1632 {
1633 case Scharquote:
1634 case Sescape:
1635 from++;
1636 startquotedinstring:
1637 if (from >= end) goto endquoted;
1638 }
1639 from++;
1640 }
1641 state.instring = -1;
1642 curlevel->prev = curlevel->last;
1643 from++;
1644 break;
1645
1646 case Smath:
1647 break;
1648 }
1649 }
1650 goto done;
1651
1652 stop: /* Here if stopping before start of sexp. */
1653 from--; /* We have just fetched the char that starts it; */
1654 goto done; /* but return the position before it. */
1655
1656 endquoted:
1657 state.quoted = 1;
1658 done:
1659 state.depth = depth;
1660 state.mindepth = mindepth;
1661 state.thislevelstart = curlevel->prev;
1662 state.prevlevelstart
1663 = (curlevel == levelstart) ? -1 : (curlevel - 1)->last;
1664 state.location = from;
1665 immediate_quit = 0;
1666
e5d4f4dc 1667 *stateptr = state;
8489eb67
RS
1668}
1669
1670/* This comment supplies the doc string for parse-partial-sexp,
1671 for make-docfile to see. We cannot put this in the real DEFUN
1672 due to limits in the Unix cpp.
1673
c81a3712 1674DEFUN ("parse-partial-sexp", Ffoo, Sfoo, 2, 6, 0,
8489eb67
RS
1675 "Parse Lisp syntax starting at FROM until TO; return status of parse at TO.\n\
1676Parsing stops at TO or when certain criteria are met;\n\
1677 point is set to where parsing stops.\n\
1678If fifth arg STATE is omitted or nil,\n\
1679 parsing assumes that FROM is the beginning of a function.\n\
e5d4f4dc 1680Value is a list of eight elements describing final state of parsing:\n\
af50f9e5
RS
1681 0. depth in parens.\n\
1682 1. character address of start of innermost containing list; nil if none.\n\
1683 2. character address of start of last complete sexp terminated.\n\
1684 3. non-nil if inside a string.\n\
8489eb67 1685 (it is the character that will terminate the string.)\n\
af50f9e5
RS
1686 4. t if inside a comment.\n\
1687 5. t if following a quote character.\n\
1688 6. the minimum paren-depth encountered during this scan.\n\
1689 7. t if in a comment of style `b'.\n\
8489eb67
RS
1690If third arg TARGETDEPTH is non-nil, parsing stops if the depth\n\
1691in parentheses becomes equal to TARGETDEPTH.\n\
1692Fourth arg STOPBEFORE non-nil means stop when come to\n\
1693 any character that starts a sexp.\n\
ec11639d 1694Fifth arg STATE is an eight-list like what this function returns.\n\
a4275ad1 1695It is used to initialize the state of the parse. Its second and third
c81a3712
RS
1696elements are ignored.
1697Sixth args COMMENTSTOP non-nil means stop at the start of a comment.")
1698 (from, to, targetdepth, stopbefore, state, commentstop)
8489eb67
RS
1699*/
1700
c81a3712 1701DEFUN ("parse-partial-sexp", Fparse_partial_sexp, Sparse_partial_sexp, 2, 6, 0,
8489eb67 1702 0 /* See immediately above */)
c81a3712
RS
1703 (from, to, targetdepth, stopbefore, oldstate, commentstop)
1704 Lisp_Object from, to, targetdepth, stopbefore, oldstate, commentstop;
8489eb67
RS
1705{
1706 struct lisp_parse_state state;
1707 int target;
1708
265a9e55 1709 if (!NILP (targetdepth))
8489eb67
RS
1710 {
1711 CHECK_NUMBER (targetdepth, 3);
1712 target = XINT (targetdepth);
1713 }
1714 else
1715 target = -100000; /* We won't reach this depth */
1716
1717 validate_region (&from, &to);
e5d4f4dc 1718 scan_sexps_forward (&state, XINT (from), XINT (to),
c81a3712
RS
1719 target, !NILP (stopbefore), oldstate,
1720 !NILP (commentstop));
8489eb67
RS
1721
1722 SET_PT (state.location);
1723
1724 return Fcons (make_number (state.depth),
1725 Fcons (state.prevlevelstart < 0 ? Qnil : make_number (state.prevlevelstart),
1726 Fcons (state.thislevelstart < 0 ? Qnil : make_number (state.thislevelstart),
1727 Fcons (state.instring >= 0 ? make_number (state.instring) : Qnil,
1728 Fcons (state.incomment ? Qt : Qnil,
1729 Fcons (state.quoted ? Qt : Qnil,
e5d4f4dc
RS
1730 Fcons (make_number (state.mindepth),
1731 Fcons (state.comstyle ? Qt : Qnil,
1732 Qnil))))))));
8489eb67
RS
1733}
1734\f
1735init_syntax_once ()
1736{
1737 register int i;
8ea151b2 1738 Lisp_Object temp;
8489eb67 1739
5ebaddf5
RS
1740 /* This has to be done here, before we call Fmake_char_table. */
1741 Qsyntax_table = intern ("syntax-table");
1742 staticpro (&Qsyntax_table);
1743
1744 /* Intern this now in case it isn't already done.
1745 Setting this variable twice is harmless.
1746 But don't staticpro it here--that is done in alloc.c. */
1747 Qchar_table_extra_slots = intern ("char-table-extra-slots");
1748
1749 /* Now we are ready to set up this property, so we can
1750 create syntax tables. */
1751 Fput (Qsyntax_table, Qchar_table_extra_slots, make_number (0));
1752
8ea151b2 1753 temp = Fcons (make_number ((int) Swhitespace), Qnil);
8489eb67 1754
5ebaddf5 1755 Vstandard_syntax_table = Fmake_char_table (Qsyntax_table, temp);
8489eb67 1756
8ea151b2 1757 temp = Fcons (make_number ((int) Sword), Qnil);
8489eb67 1758 for (i = 'a'; i <= 'z'; i++)
8ea151b2 1759 SET_RAW_SYNTAX_ENTRY (Vstandard_syntax_table, i, temp);
8489eb67 1760 for (i = 'A'; i <= 'Z'; i++)
8ea151b2 1761 SET_RAW_SYNTAX_ENTRY (Vstandard_syntax_table, i, temp);
8489eb67 1762 for (i = '0'; i <= '9'; i++)
8ea151b2
RS
1763 SET_RAW_SYNTAX_ENTRY (Vstandard_syntax_table, i, temp);
1764
1765 SET_RAW_SYNTAX_ENTRY (Vstandard_syntax_table, '$', temp);
1766 SET_RAW_SYNTAX_ENTRY (Vstandard_syntax_table, '%', temp);
1767
1768 SET_RAW_SYNTAX_ENTRY (Vstandard_syntax_table, '(',
1769 Fcons (make_number (Sopen), make_number (')')));
1770 SET_RAW_SYNTAX_ENTRY (Vstandard_syntax_table, ')',
1771 Fcons (make_number (Sclose), make_number ('(')));
1772 SET_RAW_SYNTAX_ENTRY (Vstandard_syntax_table, '[',
1773 Fcons (make_number (Sopen), make_number (']')));
1774 SET_RAW_SYNTAX_ENTRY (Vstandard_syntax_table, ']',
1775 Fcons (make_number (Sclose), make_number ('[')));
1776 SET_RAW_SYNTAX_ENTRY (Vstandard_syntax_table, '{',
1777 Fcons (make_number (Sopen), make_number ('}')));
1778 SET_RAW_SYNTAX_ENTRY (Vstandard_syntax_table, '}',
1779 Fcons (make_number (Sclose), make_number ('{')));
1780 SET_RAW_SYNTAX_ENTRY (Vstandard_syntax_table, '"',
1781 Fcons (make_number ((int) Sstring), Qnil));
1782 SET_RAW_SYNTAX_ENTRY (Vstandard_syntax_table, '\\',
1783 Fcons (make_number ((int) Sescape), Qnil));
1784
1785 temp = Fcons (make_number ((int) Ssymbol), Qnil);
8489eb67 1786 for (i = 0; i < 10; i++)
8ea151b2 1787 SET_RAW_SYNTAX_ENTRY (Vstandard_syntax_table, "_-+*/&|<>="[i], temp);
8489eb67 1788
8ea151b2 1789 temp = Fcons (make_number ((int) Spunct), Qnil);
8489eb67 1790 for (i = 0; i < 12; i++)
8ea151b2 1791 SET_RAW_SYNTAX_ENTRY (Vstandard_syntax_table, ".,;:?!#@~^'`"[i], temp);
8489eb67
RS
1792}
1793
1794syms_of_syntax ()
1795{
1796 Qsyntax_table_p = intern ("syntax-table-p");
1797 staticpro (&Qsyntax_table_p);
1798
1799 DEFVAR_BOOL ("parse-sexp-ignore-comments", &parse_sexp_ignore_comments,
1800 "Non-nil means `forward-sexp', etc., should treat comments as whitespace.");
1801
1802 words_include_escapes = 0;
1803 DEFVAR_BOOL ("words-include-escapes", &words_include_escapes,
1804 "Non-nil means `forward-word', etc., should treat escape chars part of words.");
1805
1806 defsubr (&Ssyntax_table_p);
1807 defsubr (&Ssyntax_table);
1808 defsubr (&Sstandard_syntax_table);
1809 defsubr (&Scopy_syntax_table);
1810 defsubr (&Sset_syntax_table);
1811 defsubr (&Schar_syntax);
beefa22e 1812 defsubr (&Smatching_paren);
8489eb67
RS
1813 defsubr (&Smodify_syntax_entry);
1814 defsubr (&Sdescribe_syntax);
1815
1816 defsubr (&Sforward_word);
1817
b3cfe0c8 1818 defsubr (&Sforward_comment);
8489eb67
RS
1819 defsubr (&Sscan_lists);
1820 defsubr (&Sscan_sexps);
1821 defsubr (&Sbackward_prefix_chars);
1822 defsubr (&Sparse_partial_sexp);
1823}