import xemacs-21.2.37
[chise/xemacs-chise.git.1] / src / syntax.c
1 /* XEmacs routines to deal with syntax tables; also word and list parsing.
2    Copyright (C) 1985-1994 Free Software Foundation, Inc.
3    Copyright (C) 1995 Sun Microsystems, Inc.
4
5 This file is part of XEmacs.
6
7 XEmacs is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 2, or (at your option) any
10 later version.
11
12 XEmacs is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with XEmacs; see the file COPYING.  If not, write to
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA.  */
21
22 /* Synched up with: FSF 19.28. */
23
24 /* This file has been Mule-ized. */
25
26 #include <config.h>
27 #include "lisp.h"
28
29 #include "buffer.h"
30 #include "syntax.h"
31
32 /* Here is a comment from Ken'ichi HANDA <handa@etl.go.jp>
33    explaining the purpose of the Sextword syntax category:
34
35 Japanese words are not separated by spaces, which makes finding word
36 boundaries very difficult.  Theoretically it's impossible without
37 using natural language processing techniques.  But, by defining
38 pseudo-words as below (much simplified for letting you understand it
39 easily) for Japanese, we can have a convenient forward-word function
40 for Japanese.
41
42         A Japanese word is a sequence of characters that consists of
43         zero or more Kanji characters followed by zero or more
44         Hiragana characters.
45
46 Then, the problem is that now we can't say that a sequence of
47 word-constituents makes up a WORD.  For instance, both Hiragana "A"
48 and Kanji "KAN" are word-constituents but the sequence of these two
49 letters can't be a single word.
50
51 So, we introduced Sextword for Japanese letters.  A character of
52 Sextword is a word-constituent but a word boundary may exist between
53 two such characters.  */
54
55 /* Mule 2.4 doesn't seem to have Sextword - I'm removing it -- mrb */
56 /* Recovered by tomo */
57
58 Lisp_Object Qsyntax_table_p;
59
60 int words_include_escapes;
61
62 int parse_sexp_ignore_comments;
63
64 /* The following two variables are provided to tell additional information
65    to the regex routines.  We do it this way rather than change the
66    arguments to re_search_2() in an attempt to maintain some call
67    compatibility with other versions of the regex code. */
68
69 /* Tell the regex routines not to QUIT.  Normally there is a QUIT
70    each iteration in re_search_2(). */
71 int no_quit_in_re_search;
72
73 /* Tell the regex routines which buffer to access for SYNTAX() lookups
74    and the like. */
75 struct buffer *regex_emacs_buffer;
76
77 /* Tell the regex routines whether buffer is used or not. */
78 int regex_emacs_buffer_p;
79
80 Lisp_Object Vstandard_syntax_table;
81
82 Lisp_Object Vsyntax_designator_chars_string;
83
84 /* This is the internal form of the parse state used in parse-partial-sexp.  */
85
86 struct lisp_parse_state
87 {
88   int depth;            /* Depth at end of parsing */
89   Emchar instring;      /* -1 if not within string, else desired terminator */
90   int incomment;        /* Nonzero if within a comment at end of parsing */
91   int comstyle;         /* comment style a=0, or b=1 */
92   int quoted;           /* Nonzero if just after an escape char at end of
93                            parsing */
94   Bufpos thislevelstart;/* Char number of most recent start-of-expression
95                            at current level */
96   Bufpos prevlevelstart;/* Char number of start of containing expression */
97   Bufpos location;      /* Char number at which parsing stopped */
98   int mindepth;         /* Minimum depth seen while scanning  */
99   Bufpos comstart;      /* Position just after last comment starter  */
100 };
101 \f
102 /* These variables are a cache for finding the start of a defun.
103    find_start_pos    is the place for which the defun start was found.
104    find_start_value  is the defun start position found for it.
105    find_start_buffer is the buffer it was found in.
106    find_start_begv   is the BEGV value when it was found.
107    find_start_modiff is the value of MODIFF when it was found.  */
108
109 static Bufpos find_start_pos;
110 static Bufpos find_start_value;
111 static struct buffer *find_start_buffer;
112 static Bufpos find_start_begv;
113 static int find_start_modiff;
114
115 /* Find a defun-start that is the last one before POS (or nearly the last).
116    We record what we find, so that another call in the same area
117    can return the same value right away.  */
118
119 static Bufpos
120 find_defun_start (struct buffer *buf, Bufpos pos)
121 {
122   Bufpos tem;
123   Lisp_Char_Table *mirrortab = XCHAR_TABLE (buf->mirror_syntax_table);
124
125   /* Use previous finding, if it's valid and applies to this inquiry.  */
126   if (buf == find_start_buffer
127       /* Reuse the defun-start even if POS is a little farther on.
128          POS might be in the next defun, but that's ok.
129          Our value may not be the best possible, but will still be usable.  */
130       && pos <= find_start_pos + 1000
131       && pos >= find_start_value
132       && BUF_BEGV (buf) == find_start_begv
133       && BUF_MODIFF (buf) == find_start_modiff)
134     return find_start_value;
135
136   /* Back up to start of line.  */
137   tem = find_next_newline (buf, pos, -1);
138
139   while (tem > BUF_BEGV (buf))
140     {
141       /* Open-paren at start of line means we found our defun-start.  */
142       if (SYNTAX (mirrortab, BUF_FETCH_CHAR (buf, tem)) == Sopen)
143         break;
144       /* Move to beg of previous line.  */
145       tem = find_next_newline (buf, tem, -2);
146     }
147
148   /* Record what we found, for the next try.  */
149   find_start_value  = tem;
150   find_start_buffer = buf;
151   find_start_modiff = BUF_MODIFF (buf);
152   find_start_begv   = BUF_BEGV (buf);
153   find_start_pos    = pos;
154
155   return find_start_value;
156 }
157 \f
158 DEFUN ("syntax-table-p", Fsyntax_table_p, 1, 1, 0, /*
159 Return t if OBJECT is a syntax table.
160 Any vector of 256 elements will do.
161 */
162        (object))
163 {
164   return (CHAR_TABLEP (object)
165           && XCHAR_TABLE_TYPE (object) == CHAR_TABLE_TYPE_SYNTAX)
166     ? Qt : Qnil;
167 }
168
169 static Lisp_Object
170 check_syntax_table (Lisp_Object obj, Lisp_Object default_)
171 {
172   if (NILP (obj))
173     obj = default_;
174   while (NILP (Fsyntax_table_p (obj)))
175     obj = wrong_type_argument (Qsyntax_table_p, obj);
176   return obj;
177 }
178
179 DEFUN ("syntax-table", Fsyntax_table, 0, 1, 0, /*
180 Return the current syntax table.
181 This is the one specified by the current buffer, or by BUFFER if it
182 is non-nil.
183 */
184        (buffer))
185 {
186   return decode_buffer (buffer, 0)->syntax_table;
187 }
188
189 DEFUN ("standard-syntax-table", Fstandard_syntax_table, 0, 0, 0, /*
190 Return the standard syntax table.
191 This is the one used for new buffers.
192 */
193        ())
194 {
195   return Vstandard_syntax_table;
196 }
197
198 DEFUN ("copy-syntax-table", Fcopy_syntax_table, 0, 1, 0, /*
199 Return a new syntax table which is a copy of SYNTAX-TABLE.
200 SYNTAX-TABLE defaults to the standard syntax table.
201 */
202        (syntax_table))
203 {
204   if (NILP (Vstandard_syntax_table))
205     return Fmake_char_table (Qsyntax);
206
207   syntax_table = check_syntax_table (syntax_table, Vstandard_syntax_table);
208   return Fcopy_char_table (syntax_table);
209 }
210
211 DEFUN ("set-syntax-table", Fset_syntax_table, 1, 2, 0, /*
212 Select SYNTAX-TABLE as the new syntax table for BUFFER.
213 BUFFER defaults to the current buffer if omitted.
214 */
215        (syntax_table, buffer))
216 {
217   struct buffer *buf = decode_buffer (buffer, 0);
218   syntax_table = check_syntax_table (syntax_table, Qnil);
219   buf->syntax_table = syntax_table;
220   buf->mirror_syntax_table = XCHAR_TABLE (syntax_table)->mirror_table;
221   /* Indicate that this buffer now has a specified syntax table.  */
222   buf->local_var_flags |= XINT (buffer_local_flags.syntax_table);
223   return syntax_table;
224 }
225 \f
226 /* Convert a letter which signifies a syntax code
227    into the code it signifies.
228    This is used by modify-syntax-entry, and other things. */
229
230 const unsigned char syntax_spec_code[0400] =
231 { 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377,
232   0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377,
233   0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377,
234   0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377,
235   (char) Swhitespace, 0377, (char) Sstring, 0377,
236       (char) Smath, 0377, 0377, (char) Squote,
237   (char) Sopen, (char) Sclose, 0377, 0377,
238         0377, (char) Swhitespace, (char) Spunct, (char) Scharquote,
239   0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377,
240   0377, 0377, 0377, 0377,
241         (char) Scomment, 0377, (char) Sendcomment, 0377,
242   (char) Sinherit, 0377, 0377, 0377, 0377, 0377, 0377, 0377,   /* @, A ... */
243   0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377,
244   0377, 0377, 0377, 0377, 0377, 0377, 0377, (char) Sword,
245   0377, 0377, 0377, 0377, (char) Sescape, 0377, 0377, (char) Ssymbol,
246   0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377,   /* `, a, ... */
247   0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377,
248   0377, 0377, 0377, 0377, 0377, 0377, 0377, (char) Sword,
249   0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377
250 };
251
252 const unsigned char syntax_code_spec[] =  " .w_()'\"$\\/<>@";
253
254 DEFUN ("syntax-designator-chars", Fsyntax_designator_chars, 0, 0, 0, /*
255 Return a string of the recognized syntax designator chars.
256 The chars are ordered by their internal syntax codes, which are
257 numbered starting at 0.
258 */
259        ())
260 {
261   return Vsyntax_designator_chars_string;
262 }
263
264 DEFUN ("char-syntax", Fchar_syntax, 1, 2, 0, /*
265 Return the syntax code of CHARACTER, described by a character.
266 For example, if CHARACTER is a word constituent,
267 the character `?w' is returned.
268 The characters that correspond to various syntax codes
269 are listed in the documentation of `modify-syntax-entry'.
270 Optional second argument SYNTAX-TABLE defaults to the current buffer's
271 syntax table.
272 */
273        (character, syntax_table))
274 {
275   Lisp_Char_Table *mirrortab;
276
277   if (NILP (character))
278     {
279       character = make_char ('\000');
280     }
281   CHECK_CHAR_COERCE_INT (character);
282   syntax_table = check_syntax_table (syntax_table, current_buffer->syntax_table);
283   mirrortab = XCHAR_TABLE (XCHAR_TABLE (syntax_table)->mirror_table);
284   return make_char (syntax_code_spec[(int) SYNTAX (mirrortab, XCHAR (character))]);
285 }
286
287 #ifdef MULE
288
289 enum syntaxcode
290 charset_syntax (struct buffer *buf, Lisp_Object charset, int *multi_p_out)
291 {
292   *multi_p_out = 1;
293   /* #### get this right */
294   return Spunct;
295 }
296
297 #endif
298
299 Lisp_Object
300 syntax_match (Lisp_Object syntax_table, Emchar ch)
301 {
302   Lisp_Object code = XCHAR_TABLE_VALUE_UNSAFE (syntax_table, ch);
303   Lisp_Object code2 = code;
304
305   if (CONSP (code))
306     code2 = XCAR (code);
307   if (SYNTAX_FROM_CODE (XINT (code2)) == Sinherit)
308     code = XCHAR_TABLE_VALUE_UNSAFE (Vstandard_syntax_table, ch);
309
310   return CONSP (code) ? XCDR (code) : Qnil;
311 }
312
313 DEFUN ("matching-paren", Fmatching_paren, 1, 2, 0, /*
314 Return the matching parenthesis of CHARACTER, or nil if none.
315 Optional second argument SYNTAX-TABLE defaults to the current buffer's
316 syntax table.
317 */
318        (character, syntax_table))
319 {
320   Lisp_Char_Table *mirrortab;
321   int code;
322
323   CHECK_CHAR_COERCE_INT (character);
324   syntax_table = check_syntax_table (syntax_table, current_buffer->syntax_table);
325   mirrortab = XCHAR_TABLE (XCHAR_TABLE (syntax_table)->mirror_table);
326   code = SYNTAX (mirrortab, XCHAR (character));
327   if (code == Sopen || code == Sclose || code == Sstring)
328     return syntax_match (syntax_table, XCHAR (character));
329   return Qnil;
330 }
331
332 \f
333
334 #ifdef MULE
335 /* Return 1 if there is a word boundary between two word-constituent
336    characters C1 and C2 if they appear in this order, else return 0.
337    There is no word boundary between two word-constituent ASCII
338    characters.  */
339 #define WORD_BOUNDARY_P(c1, c2)                 \
340   (!(CHAR_ASCII_P (c1) && CHAR_ASCII_P (c2))    \
341    && word_boundary_p (c1, c2))
342
343 extern int word_boundary_p (Emchar c1, Emchar c2);
344 #endif
345
346 /* Return the position across COUNT words from FROM.
347    If that many words cannot be found before the end of the buffer, return 0.
348    COUNT negative means scan backward and stop at word beginning.  */
349
350 Bufpos
351 scan_words (struct buffer *buf, Bufpos from, int count)
352 {
353   Bufpos limit = count > 0 ? BUF_ZV (buf) : BUF_BEGV (buf);
354   Lisp_Char_Table *mirrortab = XCHAR_TABLE (buf->mirror_syntax_table);
355   Emchar ch0, ch1;
356   enum syntaxcode code;
357
358   /* #### is it really worth it to hand expand both cases? JV */
359   while (count > 0)
360     {
361       QUIT;
362
363       while (1)
364         {
365           if (from == limit)
366             return 0;
367
368           ch0 = BUF_FETCH_CHAR (buf, from);
369           code = SYNTAX_UNSAFE (mirrortab, ch0);
370
371           from++;
372           if (words_include_escapes
373               && (code == Sescape || code == Scharquote))
374             break;
375           if (code == Sword)
376             break;
377         }
378
379       QUIT;
380
381       while (from != limit)
382         {
383           ch1 = BUF_FETCH_CHAR (buf, from);
384           code = SYNTAX_UNSAFE (mirrortab, ch1);
385           if (!(words_include_escapes
386                 && (code == Sescape || code == Scharquote)))
387             if (code != Sword
388 #ifdef MULE
389                 || WORD_BOUNDARY_P (ch0, ch1)
390 #endif
391                 )
392               break;
393 #ifdef MULE
394           ch0 = ch1;
395 #endif
396           from++;
397         }
398       count--;
399     }
400
401   while (count < 0)
402     {
403       QUIT;
404
405       while (1)
406         {
407           if (from == limit)
408             return 0;
409
410           ch1 = BUF_FETCH_CHAR (buf, from - 1);
411           code = SYNTAX_UNSAFE (mirrortab, ch1);
412
413           from--;
414           if (words_include_escapes
415               && (code == Sescape || code == Scharquote))
416             break;
417           if (code == Sword)
418             break;
419         }
420
421       QUIT;
422
423       while (from != limit)
424         {
425           ch0 = BUF_FETCH_CHAR (buf, from - 1);
426           code = SYNTAX_UNSAFE (mirrortab, ch0);
427           if (!(words_include_escapes
428                 && (code == Sescape || code == Scharquote)))
429             if (code != Sword
430 #ifdef MULE
431                 || WORD_BOUNDARY_P (ch0, ch1)
432 #endif
433                 )
434               break;
435 #ifdef MULE
436           ch1 = ch0;
437 #endif
438           from--;
439         }
440       count++;
441     }
442
443   return from;
444 }
445
446 DEFUN ("forward-word", Fforward_word, 1, 2, "_p", /*
447 Move point forward COUNT words (backward if COUNT is negative).
448 Normally returns t.
449 If an edge of the buffer is reached, point is left there
450 and nil is returned.
451
452 Optional argument BUFFER defaults to the current buffer.
453 */
454        (count, buffer))
455 {
456   Bufpos val;
457   struct buffer *buf = decode_buffer (buffer, 0);
458   CHECK_INT (count);
459
460   if (!(val = scan_words (buf, BUF_PT (buf), XINT (count))))
461     {
462       BUF_SET_PT (buf, XINT (count) > 0 ? BUF_ZV (buf) : BUF_BEGV (buf));
463       return Qnil;
464     }
465   BUF_SET_PT (buf, val);
466   return Qt;
467 }
468 \f
469 static void scan_sexps_forward (struct buffer *buf,
470                                 struct lisp_parse_state *,
471                                 Bufpos from, Bufpos end,
472                                 int targetdepth, int stopbefore,
473                                 Lisp_Object oldstate,
474                                 int commentstop);
475
476 static int
477 find_start_of_comment (struct buffer *buf, Bufpos from, Bufpos stop, int mask)
478 {
479   Emchar c;
480   enum syntaxcode code;
481   Lisp_Char_Table *mirrortab = XCHAR_TABLE (buf->mirror_syntax_table);
482
483   /* Look back, counting the parity of string-quotes,
484      and recording the comment-starters seen.
485      When we reach a safe place, assume that's not in a string;
486      then step the main scan to the earliest comment-starter seen
487      an even number of string quotes away from the safe place.
488
489      OFROM[I] is position of the earliest comment-starter seen
490      which is I+2X quotes from the comment-end.
491      PARITY is current parity of quotes from the comment end.  */
492   int parity = 0;
493   Emchar my_stringend = 0;
494   int string_lossage = 0;
495   Bufpos comment_end = from;
496   Bufpos comstart_pos = 0;
497   int comstart_parity = 0;
498   int styles_match_p = 0;
499
500   /* At beginning of range to scan, we're outside of strings;
501      that determines quote parity to the comment-end.  */
502   while (from != stop)
503     {
504       /* Move back and examine a character.  */
505       from--;
506
507       c = BUF_FETCH_CHAR (buf, from);
508       code = SYNTAX_UNSAFE (mirrortab, c);
509
510       /* is this a 1-char comment end sequence? if so, try
511          to see if style matches previously extracted mask */
512       if (code == Sendcomment)
513         {
514           styles_match_p = SYNTAX_STYLES_MATCH_1CHAR_P (mirrortab, c, mask);
515         }
516
517       /* otherwise, is this a 2-char comment end sequence? */
518       else if (from >= stop
519                && SYNTAX_END_P (mirrortab, c, BUF_FETCH_CHAR (buf, from+1)))
520         {
521           code = Sendcomment;
522           styles_match_p =
523             SYNTAX_STYLES_MATCH_END_P (mirrortab, c,
524                                        BUF_FETCH_CHAR (buf, from+1),
525                                        mask);
526         }
527
528       /* or are we looking at a 1-char comment start sequence
529          of the style matching mask? */
530       else if (code == Scomment
531                && SYNTAX_STYLES_MATCH_1CHAR_P (mirrortab, c, mask))
532         {
533           styles_match_p = 1;
534         }
535
536       /* or possibly, a 2-char comment start sequence */
537       else if (from >= stop
538                && SYNTAX_STYLES_MATCH_START_P (mirrortab, c,
539                                                BUF_FETCH_CHAR (buf, from+1),
540                                                mask))
541         {
542           code = Scomment;
543           styles_match_p = 1;
544         }
545
546       /* Ignore escaped characters.  */
547       if (char_quoted (buf, from))
548         continue;
549
550       /* Track parity of quotes.  */
551       if (code == Sstring)
552         {
553           parity ^= 1;
554           if (my_stringend == 0)
555             my_stringend = c;
556           /* If we have two kinds of string delimiters.
557              There's no way to grok this scanning backwards.  */
558           else if (my_stringend != c)
559             string_lossage = 1;
560         }
561
562       /* Record comment-starters according to that
563          quote-parity to the comment-end.  */
564       if (code == Scomment && styles_match_p)
565         {
566           comstart_parity = parity;
567           comstart_pos = from;
568         }
569
570       /* If we find another earlier comment-ender,
571          any comment-starts earlier than that don't count
572          (because they go with the earlier comment-ender).  */
573       if (code == Sendcomment && styles_match_p)
574         break;
575
576       /* Assume a defun-start point is outside of strings.  */
577       if (code == Sopen
578           && (from == stop || BUF_FETCH_CHAR (buf, from - 1) == '\n'))
579         break;
580     }
581
582   if (comstart_pos == 0)
583     from = comment_end;
584   /* If the earliest comment starter
585      is followed by uniform paired string quotes or none,
586      we know it can't be inside a string
587      since if it were then the comment ender would be inside one.
588      So it does start a comment.  Skip back to it.  */
589   else if (comstart_parity == 0 && !string_lossage)
590     from = comstart_pos;
591   else
592     {
593       /* We had two kinds of string delimiters mixed up
594          together.  Decode this going forwards.
595          Scan fwd from the previous comment ender
596          to the one in question; this records where we
597          last passed a comment starter.  */
598
599       struct lisp_parse_state state;
600       scan_sexps_forward (buf, &state, find_defun_start (buf, comment_end),
601                           comment_end - 1, -10000, 0, Qnil, 0);
602       if (state.incomment)
603         from = state.comstart;
604       else
605         /* We can't grok this as a comment; scan it normally.  */
606         from = comment_end;
607     }
608   return from;
609 }
610
611 static Bufpos
612 find_end_of_comment (struct buffer *buf, Bufpos from, Bufpos stop, int mask)
613 {
614   int c;
615   Lisp_Char_Table *mirrortab = XCHAR_TABLE (buf->mirror_syntax_table);
616
617   while (1)
618     {
619       if (from == stop)
620         {
621           return -1;
622         }
623       c = BUF_FETCH_CHAR (buf, from);
624       if (SYNTAX_UNSAFE (mirrortab, c) == Sendcomment
625           && SYNTAX_STYLES_MATCH_1CHAR_P (mirrortab, c, mask))
626         /* we have encountered a comment end of the same style
627            as the comment sequence which began this comment
628            section */
629         break;
630
631       from++;
632       if (from < stop
633           && SYNTAX_STYLES_MATCH_END_P (mirrortab, c,
634                                         BUF_FETCH_CHAR (buf, from), mask))
635         /* we have encountered a comment end of the same style
636            as the comment sequence which began this comment
637            section */
638         { from++; break; }
639     }
640   return from;
641 }
642
643 \f
644 /* #### between FSF 19.23 and 19.28 there are some changes to the logic
645    in this function (and minor changes to find_start_of_comment(),
646    above, which is part of Fforward_comment() in FSF).  Attempts to port
647    that logic made this function break, so I'm leaving it out.  If anyone
648    ever complains about this function not working properly, take a look
649    at those changes.  --ben */
650
651 DEFUN ("forward-comment", Fforward_comment, 1, 2, 0, /*
652 Move forward across up to COUNT comments, or backwards if COUNT is negative.
653 Stop scanning if we find something other than a comment or whitespace.
654 Set point to where scanning stops.
655 If COUNT comments are found as expected, with nothing except whitespace
656 between them, return t; otherwise return nil.
657 Point is set in either case.
658 Optional argument BUFFER defaults to the current buffer.
659 */
660        (count, buffer))
661 {
662   Bufpos from;
663   Bufpos stop;
664   Emchar c;
665   enum syntaxcode code;
666   EMACS_INT n;
667   struct buffer *buf = decode_buffer (buffer, 0);
668   Lisp_Char_Table *mirrortab = XCHAR_TABLE (buf->mirror_syntax_table);
669
670   CHECK_INT (count);
671   n = XINT (count);
672
673   from = BUF_PT (buf);
674
675   while (n > 0)
676     {
677       QUIT;
678
679       stop = BUF_ZV (buf);
680       while (from < stop)
681         {
682           int mask = 0;         /* mask for finding matching comment style */
683
684           if (char_quoted (buf, from))
685             {
686               from++;
687               continue;
688             }
689
690           c = BUF_FETCH_CHAR (buf, from);
691           code = SYNTAX (mirrortab, c);
692
693           if (code == Scomment)
694             {
695               /* we have encountered a single character comment start
696                  sequence, and we are ignoring all text inside comments.
697                  we must record the comment style this character begins
698                  so that later, only a comment end of the same style actually
699                  ends the comment section */
700               mask = SYNTAX_COMMENT_1CHAR_MASK (mirrortab, c);
701             }
702
703           else if (from < stop
704                    && SYNTAX_START_P (mirrortab, c, BUF_FETCH_CHAR (buf, from+1)))
705             {
706               /* we have encountered a 2char comment start sequence and we
707                  are ignoring all text inside comments. we must record
708                  the comment style this sequence begins so that later,
709                  only a comment end of the same style actually ends
710                  the comment section */
711               code = Scomment;
712               mask = SYNTAX_COMMENT_MASK_START (mirrortab, c,
713                                                 BUF_FETCH_CHAR (buf, from+1));
714               from++;
715             }
716
717           if (code == Scomment)
718             {
719               Bufpos newfrom;
720
721               newfrom = find_end_of_comment (buf, from, stop, mask);
722               if (newfrom < 0)
723                 {
724                   /* we stopped because from==stop */
725                   BUF_SET_PT (buf, stop);
726                   return Qnil;
727                 }
728               from = newfrom;
729
730               /* We have skipped one comment.  */
731               break;
732             }
733           else if (code != Swhitespace
734                    && code != Sendcomment
735                    && code != Scomment )
736             {
737               BUF_SET_PT (buf, from);
738               return Qnil;
739             }
740           from++;
741         }
742
743       /* End of comment reached */
744       n--;
745     }
746
747   while (n < 0)
748     {
749       QUIT;
750
751       stop = BUF_BEGV (buf);
752       while (from > stop)
753         {
754           int mask = 0;         /* mask for finding matching comment style */
755
756           from--;
757           if (char_quoted (buf, from))
758             {
759               from--;
760               continue;
761             }
762
763           c = BUF_FETCH_CHAR (buf, from);
764           code = SYNTAX (mirrortab, c);
765
766           if (code == Sendcomment)
767             {
768               /* we have found a single char end comment. we must record
769                  the comment style encountered so that later, we can match
770                  only the proper comment begin sequence of the same style */
771               mask = SYNTAX_COMMENT_1CHAR_MASK (mirrortab, c);
772             }
773
774           else if (from > stop
775                    && SYNTAX_END_P (mirrortab, BUF_FETCH_CHAR (buf, from - 1), c)
776                    && !char_quoted (buf, from - 1))
777             {
778               /* We must record the comment style encountered so that
779                  later, we can match only the proper comment begin
780                  sequence of the same style.  */
781               code = Sendcomment;
782               mask = SYNTAX_COMMENT_MASK_END (mirrortab,
783                                               BUF_FETCH_CHAR (buf, from - 1),
784                                               c);
785               from--;
786             }
787
788           if (code == Sendcomment)
789             {
790               from = find_start_of_comment (buf, from, stop, mask);
791               break;
792             }
793
794           else if (code != Swhitespace
795                    && SYNTAX (mirrortab, c) != Scomment
796                    && SYNTAX (mirrortab, c) != Sendcomment)
797             {
798               BUF_SET_PT (buf, from + 1);
799               return Qnil;
800             }
801         }
802
803       n++;
804     }
805
806   BUF_SET_PT (buf, from);
807   return Qt;
808 }
809
810 \f
811 Lisp_Object
812 scan_lists (struct buffer *buf, Bufpos from, int count, int depth,
813             int sexpflag, int noerror)
814 {
815   Bufpos stop;
816   Emchar c;
817   int quoted;
818   int mathexit = 0;
819   enum syntaxcode code;
820   int min_depth = depth;    /* Err out if depth gets less than this. */
821   Lisp_Object syntaxtab = buf->syntax_table;
822   Lisp_Char_Table *mirrortab = XCHAR_TABLE (buf->mirror_syntax_table);
823
824   if (depth > 0) min_depth = 0;
825
826   while (count > 0)
827     {
828       QUIT;
829
830       stop = BUF_ZV (buf);
831       while (from < stop)
832         {
833           int mask = 0;         /* mask for finding matching comment style */
834
835           c = BUF_FETCH_CHAR (buf, from);
836           code = SYNTAX_UNSAFE (mirrortab, c);
837           from++;
838
839           /* a 1-char comment start sequence */
840           if (code == Scomment && parse_sexp_ignore_comments)
841             {
842               mask = SYNTAX_COMMENT_1CHAR_MASK (mirrortab, c);
843             }
844
845           /* else, a 2-char comment start sequence? */
846           else if (from < stop
847                    && SYNTAX_START_P (mirrortab, c, BUF_FETCH_CHAR (buf, from))
848                    && parse_sexp_ignore_comments)
849             {
850               /* we have encountered a comment start sequence and we
851                  are ignoring all text inside comments. we must record
852                  the comment style this sequence begins so that later,
853                  only a comment end of the same style actually ends
854                  the comment section */
855               code = Scomment;
856               mask = SYNTAX_COMMENT_MASK_START (mirrortab, c,
857                                                 BUF_FETCH_CHAR (buf, from));
858               from++;
859             }
860
861           if (SYNTAX_PREFIX_UNSAFE (mirrortab, c))
862             continue;
863
864           switch (code)
865             {
866             case Sescape:
867             case Scharquote:
868               if (from == stop) goto lose;
869               from++;
870               /* treat following character as a word constituent */
871             case Sword:
872             case Ssymbol:
873               if (depth || !sexpflag) break;
874               /* This word counts as a sexp; return at end of it. */
875               while (from < stop)
876                 {
877                   switch (SYNTAX (mirrortab, BUF_FETCH_CHAR (buf, from)))
878                     {
879                     case Scharquote:
880                     case Sescape:
881                       from++;
882                       if (from == stop) goto lose;
883                       break;
884                     case Sword:
885                     case Ssymbol:
886                     case Squote:
887                       break;
888                     default:
889                       goto done;
890                     }
891                   from++;
892                 }
893               goto done;
894
895             case Scomment:
896               if (!parse_sexp_ignore_comments)
897                 break;
898               {
899                 Bufpos newfrom = find_end_of_comment (buf, from, stop, mask);
900                 if (newfrom < 0)
901                   {
902                     /* we stopped because from == stop in search forward */
903                     from = stop;
904                     if (depth == 0)
905                       goto done;
906                     goto lose;
907                   }
908                 from = newfrom;
909               }
910               break;
911
912             case Smath:
913               if (!sexpflag)
914                 break;
915               if (from != stop && c == BUF_FETCH_CHAR (buf, from))
916                 from++;
917               if (mathexit)
918                 {
919                   mathexit = 0;
920                   goto close1;
921                 }
922               mathexit = 1;
923
924             case Sopen:
925               if (!++depth) goto done;
926               break;
927
928             case Sclose:
929             close1:
930             if (!--depth) goto done;
931             if (depth < min_depth)
932               {
933                 if (noerror)
934                   return Qnil;
935                 error ("Containing expression ends prematurely");
936               }
937             break;
938
939             case Sstring:
940               {
941                 /* XEmacs change: call syntax_match on character */
942                 Emchar ch = BUF_FETCH_CHAR (buf, from - 1);
943                 Lisp_Object stermobj = syntax_match (syntaxtab, ch);
944                 Emchar stringterm;
945
946                 if (CHARP (stermobj))
947                   stringterm = XCHAR (stermobj);
948                 else
949                   stringterm = ch;
950
951                 while (1)
952                   {
953                     if (from >= stop)
954                       goto lose;
955                     if (BUF_FETCH_CHAR (buf, from) == stringterm)
956                       break;
957                     switch (SYNTAX (mirrortab, BUF_FETCH_CHAR (buf, from)))
958                       {
959                       case Scharquote:
960                       case Sescape:
961                         from++;
962                         break;
963                       default:
964                         break;
965                       }
966                     from++;
967                   }
968                 from++;
969                 if (!depth && sexpflag) goto done;
970                 break;
971               }
972
973             default:
974               break;
975             }
976         }
977
978       /* Reached end of buffer.  Error if within object,
979          return nil if between */
980       if (depth) goto lose;
981
982       return Qnil;
983
984       /* End of object reached */
985     done:
986       count--;
987     }
988
989   while (count < 0)
990     {
991       QUIT;
992
993       stop = BUF_BEGV (buf);
994       while (from > stop)
995         {
996           int mask = 0;         /* mask for finding matching comment style */
997
998           from--;
999           quoted = char_quoted (buf, from);
1000           if (quoted)
1001             from--;
1002
1003           c = BUF_FETCH_CHAR (buf, from);
1004           code = SYNTAX_UNSAFE (mirrortab, c);
1005
1006           if (code == Sendcomment && parse_sexp_ignore_comments)
1007             {
1008               /* we have found a single char end comment. we must record
1009                  the comment style encountered so that later, we can match
1010                  only the proper comment begin sequence of the same style */
1011               mask = SYNTAX_COMMENT_1CHAR_MASK (mirrortab, c);
1012             }
1013
1014           else if (from > stop
1015                    && SYNTAX_END_P (mirrortab, BUF_FETCH_CHAR (buf, from-1), c)
1016                    && !char_quoted (buf, from - 1)
1017                    && parse_sexp_ignore_comments)
1018             {
1019               /* we must record the comment style encountered so that
1020                  later, we can match only the proper comment begin
1021                  sequence of the same style */
1022               code = Sendcomment;
1023               mask = SYNTAX_COMMENT_MASK_END (mirrortab,
1024                                               BUF_FETCH_CHAR (buf, from - 1),
1025                                               c);
1026               from--;
1027             }
1028
1029           if (SYNTAX_PREFIX_UNSAFE (mirrortab, c))
1030             continue;
1031
1032           switch (quoted ? Sword : code)
1033             {
1034             case Sword:
1035             case Ssymbol:
1036               if (depth || !sexpflag) break;
1037               /* This word counts as a sexp; count object finished after
1038                  passing it. */
1039               while (from > stop)
1040                 {
1041                   enum syntaxcode syncode;
1042                   quoted = char_quoted (buf, from - 1);
1043
1044                   if (quoted)
1045                     from--;
1046                   if (! (quoted
1047                          || (syncode =
1048                              SYNTAX (mirrortab, BUF_FETCH_CHAR (buf, from - 1)))
1049                          == Sword
1050                          || syncode == Ssymbol
1051                          || syncode == Squote))
1052                     goto done2;
1053                   from--;
1054                 }
1055               goto done2;
1056
1057             case Smath:
1058               if (!sexpflag)
1059                 break;
1060               if (from != stop && c == BUF_FETCH_CHAR (buf, from - 1))
1061                 from--;
1062               if (mathexit)
1063                 {
1064                   mathexit = 0;
1065                   goto open2;
1066                 }
1067               mathexit = 1;
1068
1069             case Sclose:
1070               if (!++depth) goto done2;
1071               break;
1072
1073             case Sopen:
1074             open2:
1075             if (!--depth) goto done2;
1076             if (depth < min_depth)
1077               {
1078                 if (noerror)
1079                   return Qnil;
1080                 error ("Containing expression ends prematurely");
1081               }
1082             break;
1083
1084             case Sendcomment:
1085               if (parse_sexp_ignore_comments)
1086                 from = find_start_of_comment (buf, from, stop, mask);
1087               break;
1088
1089             case Sstring:
1090               {
1091                 /* XEmacs change: call syntax_match() on character */
1092                 Emchar ch = BUF_FETCH_CHAR (buf, from);
1093                 Lisp_Object stermobj = syntax_match (syntaxtab, ch);
1094                 Emchar stringterm;
1095
1096                 if (CHARP (stermobj))
1097                   stringterm = XCHAR (stermobj);
1098                 else
1099                   stringterm = ch;
1100
1101                 while (1)
1102                   {
1103                     if (from == stop) goto lose;
1104                     if (!char_quoted (buf, from - 1)
1105                         && stringterm == BUF_FETCH_CHAR (buf, from - 1))
1106                       break;
1107                     from--;
1108                   }
1109                 from--;
1110                 if (!depth && sexpflag) goto done2;
1111                 break;
1112               }
1113             }
1114         }
1115
1116       /* Reached start of buffer.  Error if within object,
1117          return nil if between */
1118       if (depth) goto lose;
1119
1120       return Qnil;
1121
1122     done2:
1123       count++;
1124     }
1125
1126
1127   return (make_int (from));
1128
1129 lose:
1130   if (!noerror)
1131     error ("Unbalanced parentheses");
1132   return Qnil;
1133 }
1134
1135 int
1136 char_quoted (struct buffer *buf, Bufpos pos)
1137 {
1138   enum syntaxcode code;
1139   Bufpos beg = BUF_BEGV (buf);
1140   int quoted = 0;
1141   Lisp_Char_Table *mirrortab = XCHAR_TABLE (buf->mirror_syntax_table);
1142
1143   while (pos > beg
1144          && ((code = SYNTAX (mirrortab, BUF_FETCH_CHAR (buf, pos - 1)))
1145              == Scharquote
1146              || code == Sescape))
1147     pos--, quoted = !quoted;
1148   return quoted;
1149 }
1150
1151 DEFUN ("scan-lists", Fscan_lists, 3, 5, 0, /*
1152 Scan from character number FROM by COUNT lists.
1153 Returns the character number of the position thus found.
1154
1155 If DEPTH is nonzero, paren depth begins counting from that value,
1156 only places where the depth in parentheses becomes zero
1157 are candidates for stopping; COUNT such places are counted.
1158 Thus, a positive value for DEPTH means go out levels.
1159
1160 Comments are ignored if `parse-sexp-ignore-comments' is non-nil.
1161
1162 If the beginning or end of (the accessible part of) the buffer is reached
1163 and the depth is wrong, an error is signaled.
1164 If the depth is right but the count is not used up, nil is returned.
1165
1166 If optional arg BUFFER is non-nil, scanning occurs in that buffer instead
1167 of in the current buffer.
1168
1169 If optional arg NOERROR is non-nil, scan-lists will return nil instead of
1170 signalling an error.
1171 */
1172        (from, count, depth, buffer, noerror))
1173 {
1174   struct buffer *buf;
1175
1176   CHECK_INT (from);
1177   CHECK_INT (count);
1178   CHECK_INT (depth);
1179   buf = decode_buffer (buffer, 0);
1180
1181   return scan_lists (buf, XINT (from), XINT (count), XINT (depth), 0,
1182                      !NILP (noerror));
1183 }
1184
1185 DEFUN ("scan-sexps", Fscan_sexps, 2, 4, 0, /*
1186 Scan from character number FROM by COUNT balanced expressions.
1187 If COUNT is negative, scan backwards.
1188 Returns the character number of the position thus found.
1189
1190 Comments are ignored if `parse-sexp-ignore-comments' is non-nil.
1191
1192 If the beginning or end of (the accessible part of) the buffer is reached
1193 in the middle of a parenthetical grouping, an error is signaled.
1194 If the beginning or end is reached between groupings
1195 but before count is used up, nil is returned.
1196
1197 If optional arg BUFFER is non-nil, scanning occurs in that buffer instead
1198 of in the current buffer.
1199
1200 If optional arg NOERROR is non-nil, scan-sexps will return nil instead of
1201 signalling an error.
1202 */
1203        (from, count, buffer, noerror))
1204 {
1205   struct buffer *buf = decode_buffer (buffer, 0);
1206   CHECK_INT (from);
1207   CHECK_INT (count);
1208
1209   return scan_lists (buf, XINT (from), XINT (count), 0, 1, !NILP (noerror));
1210 }
1211
1212 DEFUN ("backward-prefix-chars", Fbackward_prefix_chars, 0, 1, 0, /*
1213 Move point backward over any number of chars with prefix syntax.
1214 This includes chars with "quote" or "prefix" syntax (' or p).
1215
1216 Optional arg BUFFER defaults to the current buffer.
1217 */
1218        (buffer))
1219 {
1220   struct buffer *buf = decode_buffer (buffer, 0);
1221   Bufpos beg = BUF_BEGV (buf);
1222   Bufpos pos = BUF_PT (buf);
1223   Lisp_Char_Table *mirrortab = XCHAR_TABLE (buf->mirror_syntax_table);
1224
1225   while (pos > beg && !char_quoted (buf, pos - 1)
1226          && (SYNTAX (mirrortab, BUF_FETCH_CHAR (buf, pos - 1)) == Squote
1227              || SYNTAX_PREFIX (mirrortab, BUF_FETCH_CHAR (buf, pos - 1))))
1228     pos--;
1229
1230   BUF_SET_PT (buf, pos);
1231
1232   return Qnil;
1233 }
1234 \f
1235 /* Parse forward from FROM to END,
1236    assuming that FROM has state OLDSTATE (nil means FROM is start of function),
1237    and return a description of the state of the parse at END.
1238    If STOPBEFORE is nonzero, stop at the start of an atom.
1239    If COMMENTSTOP is nonzero, stop at the start of a comment.  */
1240
1241 static void
1242 scan_sexps_forward (struct buffer *buf, struct lisp_parse_state *stateptr,
1243                     Bufpos from, Bufpos end,
1244                     int targetdepth, int stopbefore,
1245                     Lisp_Object oldstate,
1246                     int commentstop)
1247 {
1248   struct lisp_parse_state state;
1249
1250   enum syntaxcode code;
1251   struct level { int last, prev; };
1252   struct level levelstart[100];
1253   struct level *curlevel = levelstart;
1254   struct level *endlevel = levelstart + 100;
1255   int depth;    /* Paren depth of current scanning location.
1256                            level - levelstart equals this except
1257                            when the depth becomes negative.  */
1258   int mindepth;         /* Lowest DEPTH value seen.  */
1259   int start_quoted = 0;         /* Nonzero means starting after a char quote */
1260   Lisp_Object tem;
1261   int mask;                                  /* comment mask */
1262   Lisp_Object syntaxtab = buf->syntax_table;
1263   Lisp_Char_Table *mirrortab = XCHAR_TABLE (buf->mirror_syntax_table);
1264
1265   if (NILP (oldstate))
1266     {
1267       depth = 0;
1268       state.instring = -1;
1269       state.incomment = 0;
1270       state.comstyle = 0;       /* comment style a by default */
1271       mask = SYNTAX_COMMENT_STYLE_A;
1272     }
1273   else
1274     {
1275       tem = Fcar (oldstate);    /* elt 0, depth */
1276       if (!NILP (tem))
1277         depth = XINT (tem);
1278       else
1279         depth = 0;
1280
1281       oldstate = Fcdr (oldstate);
1282       oldstate = Fcdr (oldstate);
1283       oldstate = Fcdr (oldstate);
1284       tem = Fcar (oldstate);    /* elt 3, instring */
1285       state.instring = !NILP (tem) ? XINT (tem) : -1;
1286
1287       oldstate = Fcdr (oldstate); /* elt 4, incomment */
1288       tem = Fcar (oldstate);
1289       state.incomment = !NILP (tem);
1290
1291       oldstate = Fcdr (oldstate);
1292       tem = Fcar (oldstate);    /* elt 5, follows-quote */
1293       start_quoted = !NILP (tem);
1294
1295       /* if the eighth element of the list is nil, we are in comment style
1296          a. if it is non-nil, we are in comment style b */
1297       oldstate = Fcdr (oldstate);
1298       oldstate = Fcdr (oldstate);
1299       oldstate = Fcdr (oldstate);
1300       tem = Fcar (oldstate);    /* elt 8, comment style a */
1301       state.comstyle = !NILP (tem);
1302       mask = state.comstyle ? SYNTAX_COMMENT_STYLE_B : SYNTAX_COMMENT_STYLE_A;
1303     }
1304   state.quoted = 0;
1305   mindepth = depth;
1306
1307   curlevel->prev = -1;
1308   curlevel->last = -1;
1309
1310   /* Enter the loop at a place appropriate for initial state. */
1311
1312   if (state.incomment) goto startincomment;
1313   if (state.instring >= 0)
1314     {
1315       if (start_quoted) goto startquotedinstring;
1316       goto startinstring;
1317     }
1318   if (start_quoted) goto startquoted;
1319
1320   while (from < end)
1321     {
1322       QUIT;
1323
1324       code = SYNTAX (mirrortab, BUF_FETCH_CHAR (buf, from));
1325       from++;
1326
1327       if (code == Scomment)
1328         {
1329           /* record the comment style we have entered so that only the
1330              comment-ender sequence (or single char) of the same style
1331              actually terminates the comment section. */
1332           mask = SYNTAX_COMMENT_1CHAR_MASK (mirrortab,
1333                                             BUF_FETCH_CHAR (buf, from-1));
1334           state.comstyle = (mask == SYNTAX_COMMENT_STYLE_B);
1335           state.comstart = from - 1;
1336         }
1337
1338       else if (from < end &&
1339                SYNTAX_START_P (mirrortab, BUF_FETCH_CHAR (buf, from-1),
1340                                BUF_FETCH_CHAR (buf, from)))
1341         {
1342           /* Record the comment style we have entered so that only
1343              the comment-end sequence of the same style actually
1344              terminates the comment section.  */
1345           code = Scomment;
1346           mask = SYNTAX_COMMENT_MASK_START (mirrortab,
1347                                             BUF_FETCH_CHAR (buf, from-1),
1348                                             BUF_FETCH_CHAR (buf, from));
1349           state.comstyle = (mask == SYNTAX_COMMENT_STYLE_B);
1350           state.comstart = from-1;
1351           from++;
1352         }
1353
1354       if (SYNTAX_PREFIX (mirrortab, BUF_FETCH_CHAR (buf, from - 1)))
1355         continue;
1356       switch (code)
1357         {
1358         case Sescape:
1359         case Scharquote:
1360           if (stopbefore) goto stop;  /* this arg means stop at sexp start */
1361           curlevel->last = from - 1;
1362         startquoted:
1363           if (from == end) goto endquoted;
1364           from++;
1365           goto symstarted;
1366           /* treat following character as a word constituent */
1367         case Sword:
1368         case Ssymbol:
1369           if (stopbefore) goto stop;  /* this arg means stop at sexp start */
1370           curlevel->last = from - 1;
1371         symstarted:
1372           while (from < end)
1373             {
1374               switch (SYNTAX (mirrortab, BUF_FETCH_CHAR (buf, from)))
1375                 {
1376                 case Scharquote:
1377                 case Sescape:
1378                   from++;
1379                   if (from == end) goto endquoted;
1380                   break;
1381                 case Sword:
1382                 case Ssymbol:
1383                 case Squote:
1384                   break;
1385                 default:
1386                   goto symdone;
1387                 }
1388               from++;
1389             }
1390         symdone:
1391           curlevel->prev = curlevel->last;
1392           break;
1393
1394         case Scomment:
1395           state.incomment = 1;
1396         startincomment:
1397           if (commentstop)
1398             goto done;
1399           {
1400             Bufpos newfrom = find_end_of_comment (buf, from, end, mask);
1401             if (newfrom < 0)
1402               {
1403                 /* we terminated search because from == end */
1404                 from = end;
1405                 goto done;
1406               }
1407             from = newfrom;
1408           }
1409           state.incomment = 0;
1410           state.comstyle = 0;                /* reset the comment style */
1411           mask = 0;
1412           break;
1413
1414         case Sopen:
1415           if (stopbefore) goto stop;  /* this arg means stop at sexp start */
1416           depth++;
1417           /* curlevel++->last ran into compiler bug on Apollo */
1418           curlevel->last = from - 1;
1419           if (++curlevel == endlevel)
1420             error ("Nesting too deep for parser");
1421           curlevel->prev = -1;
1422           curlevel->last = -1;
1423           if (targetdepth == depth) goto done;
1424           break;
1425
1426         case Sclose:
1427           depth--;
1428           if (depth < mindepth)
1429             mindepth = depth;
1430           if (curlevel != levelstart)
1431             curlevel--;
1432           curlevel->prev = curlevel->last;
1433           if (targetdepth == depth) goto done;
1434           break;
1435
1436         case Sstring:
1437           {
1438             Emchar ch;
1439             if (stopbefore) goto stop; /* this arg means stop at sexp start */
1440             curlevel->last = from - 1;
1441             /* XEmacs change: call syntax_match() on character */
1442             ch = BUF_FETCH_CHAR (buf, from - 1);
1443             {
1444               Lisp_Object stermobj = syntax_match (syntaxtab, ch);
1445
1446               if (CHARP (stermobj))
1447                 state.instring = XCHAR (stermobj);
1448               else
1449                 state.instring = ch;
1450             }
1451           }
1452         startinstring:
1453           while (1)
1454             {
1455               if (from >= end) goto done;
1456               if (BUF_FETCH_CHAR (buf, from) == state.instring) break;
1457               switch (SYNTAX (mirrortab, BUF_FETCH_CHAR (buf, from)))
1458                 {
1459                 case Scharquote:
1460                 case Sescape:
1461                   {
1462                     from++;
1463                   startquotedinstring:
1464                     if (from >= end) goto endquoted;
1465                     break;
1466                   }
1467                 default:
1468                   break;
1469                 }
1470               from++;
1471             }
1472           state.instring = -1;
1473           curlevel->prev = curlevel->last;
1474           from++;
1475           break;
1476
1477         case Smath:
1478           break;
1479
1480         case Swhitespace:
1481         case Spunct:
1482         case Squote:
1483         case Sendcomment:
1484         case Sinherit:
1485         case Smax:
1486           break;
1487         }
1488     }
1489   goto done;
1490
1491  stop:   /* Here if stopping before start of sexp. */
1492   from--;    /* We have just fetched the char that starts it; */
1493   goto done; /* but return the position before it. */
1494
1495  endquoted:
1496   state.quoted = 1;
1497  done:
1498   state.depth = depth;
1499   state.mindepth = mindepth;
1500   state.thislevelstart = curlevel->prev;
1501   state.prevlevelstart
1502     = (curlevel == levelstart) ? -1 : (curlevel - 1)->last;
1503   state.location = from;
1504
1505   *stateptr = state;
1506 }
1507
1508 DEFUN ("parse-partial-sexp", Fparse_partial_sexp, 2, 7, 0, /*
1509 Parse Lisp syntax starting at FROM until TO; return status of parse at TO.
1510 Parsing stops at TO or when certain criteria are met;
1511  point is set to where parsing stops.
1512 If fifth arg OLDSTATE is omitted or nil,
1513  parsing assumes that FROM is the beginning of a function.
1514 Value is a list of eight elements describing final state of parsing:
1515  0. depth in parens.
1516  1. character address of start of innermost containing list; nil if none.
1517  2. character address of start of last complete sexp terminated.
1518  3. non-nil if inside a string.
1519     (It is the character that will terminate the string.)
1520  4. t if inside a comment.
1521  5. t if following a quote character.
1522  6. the minimum paren-depth encountered during this scan.
1523  7. nil if in comment style a, or not in a comment; t if in comment style b
1524 If third arg TARGETDEPTH is non-nil, parsing stops if the depth
1525 in parentheses becomes equal to TARGETDEPTH.
1526 Fourth arg STOPBEFORE non-nil means stop when come to
1527  any character that starts a sexp.
1528 Fifth arg OLDSTATE is an eight-element list like what this function returns.
1529 It is used to initialize the state of the parse.  Its second and third
1530 elements are ignored.
1531 Sixth arg COMMENTSTOP non-nil means stop at the start of a comment.
1532 */
1533        (from, to, targetdepth, stopbefore, oldstate, commentstop, buffer))
1534 {
1535   struct lisp_parse_state state;
1536   int target;
1537   Bufpos start, end;
1538   struct buffer *buf = decode_buffer (buffer, 0);
1539   Lisp_Object val;
1540
1541   if (!NILP (targetdepth))
1542     {
1543       CHECK_INT (targetdepth);
1544       target = XINT (targetdepth);
1545     }
1546   else
1547     target = -100000;           /* We won't reach this depth */
1548
1549   get_buffer_range_char (buf, from, to, &start, &end, 0);
1550   scan_sexps_forward (buf, &state, start, end,
1551                       target, !NILP (stopbefore), oldstate,
1552                       !NILP (commentstop));
1553
1554   BUF_SET_PT (buf, state.location);
1555
1556   /* reverse order */
1557   val = Qnil;
1558   val = Fcons (state.comstyle  ? Qt : Qnil, val);
1559   val = Fcons (make_int (state.mindepth),   val);
1560   val = Fcons (state.quoted    ? Qt : Qnil, val);
1561   val = Fcons (state.incomment ? Qt : Qnil, val);
1562   val = Fcons (state.instring       < 0 ? Qnil : make_int (state.instring),       val);
1563   val = Fcons (state.thislevelstart < 0 ? Qnil : make_int (state.thislevelstart), val);
1564   val = Fcons (state.prevlevelstart < 0 ? Qnil : make_int (state.prevlevelstart), val);
1565   val = Fcons (make_int (state.depth), val);
1566
1567   return val;
1568 }
1569
1570
1571 /* Updating of the mirror syntax table.
1572
1573    Each syntax table has a corresponding mirror table in it.
1574    Whenever we make a change to a syntax table, we call
1575    update_syntax_table() on it.
1576
1577    #### We really only need to map over the changed range.
1578
1579    If we change the standard syntax table, we need to map over
1580    all tables because any of them could be inheriting from the
1581    standard syntax table.
1582
1583    When `set-syntax-table' is called, we set the buffer's mirror
1584    syntax table as well.
1585    */
1586
1587 struct cmst_arg
1588 {
1589   Lisp_Object mirrortab;
1590   int check_inherit;
1591 };
1592
1593 static int
1594 cmst_mapfun (struct chartab_range *range, Lisp_Object val, void *arg)
1595 {
1596   struct cmst_arg *closure = (struct cmst_arg *) arg;
1597
1598   if (CONSP (val))
1599     val = XCAR (val);
1600   if (SYNTAX_FROM_CODE (XINT (val)) == Sinherit
1601       && closure->check_inherit)
1602     {
1603       struct cmst_arg recursive;
1604
1605       recursive.mirrortab = closure->mirrortab;
1606       recursive.check_inherit = 0;
1607       map_char_table (XCHAR_TABLE (Vstandard_syntax_table), range,
1608                                    cmst_mapfun, &recursive);
1609     }
1610   else
1611     put_char_table (XCHAR_TABLE (closure->mirrortab), range, val);
1612   return 0;
1613 }
1614
1615 static void
1616 update_just_this_syntax_table (Lisp_Char_Table *ct)
1617 {
1618   struct chartab_range range;
1619   struct cmst_arg arg;
1620
1621   arg.mirrortab = ct->mirror_table;
1622   arg.check_inherit = (CHAR_TABLEP (Vstandard_syntax_table)
1623                        && ct != XCHAR_TABLE (Vstandard_syntax_table));
1624   range.type = CHARTAB_RANGE_ALL;
1625   map_char_table (ct, &range, cmst_mapfun, &arg);
1626 }
1627
1628 /* Called from chartab.c when a change is made to a syntax table.
1629    If this is the standard syntax table, we need to recompute
1630    *all* syntax tables (yuck).  Otherwise we just recompute this
1631    one. */
1632
1633 void
1634 update_syntax_table (Lisp_Char_Table *ct)
1635 {
1636   /* Don't be stymied at startup. */
1637   if (CHAR_TABLEP (Vstandard_syntax_table)
1638       && ct == XCHAR_TABLE (Vstandard_syntax_table))
1639     {
1640       Lisp_Object syntab;
1641
1642       for (syntab = Vall_syntax_tables; !NILP (syntab);
1643            syntab = XCHAR_TABLE (syntab)->next_table)
1644         update_just_this_syntax_table (XCHAR_TABLE (syntab));
1645     }
1646   else
1647     update_just_this_syntax_table (ct);
1648 }
1649
1650 \f
1651 /************************************************************************/
1652 /*                            initialization                            */
1653 /************************************************************************/
1654
1655 void
1656 syms_of_syntax (void)
1657 {
1658   defsymbol (&Qsyntax_table_p, "syntax-table-p");
1659
1660   DEFSUBR (Fsyntax_table_p);
1661   DEFSUBR (Fsyntax_table);
1662   DEFSUBR (Fstandard_syntax_table);
1663   DEFSUBR (Fcopy_syntax_table);
1664   DEFSUBR (Fset_syntax_table);
1665   DEFSUBR (Fsyntax_designator_chars);
1666   DEFSUBR (Fchar_syntax);
1667   DEFSUBR (Fmatching_paren);
1668   /* DEFSUBR (Fmodify_syntax_entry); now in Lisp. */
1669   /* DEFSUBR (Fdescribe_syntax); now in Lisp. */
1670
1671   DEFSUBR (Fforward_word);
1672
1673   DEFSUBR (Fforward_comment);
1674   DEFSUBR (Fscan_lists);
1675   DEFSUBR (Fscan_sexps);
1676   DEFSUBR (Fbackward_prefix_chars);
1677   DEFSUBR (Fparse_partial_sexp);
1678 }
1679
1680 void
1681 vars_of_syntax (void)
1682 {
1683   DEFVAR_BOOL ("parse-sexp-ignore-comments", &parse_sexp_ignore_comments /*
1684 Non-nil means `forward-sexp', etc., should treat comments as whitespace.
1685 */ );
1686   parse_sexp_ignore_comments = 0;
1687
1688   DEFVAR_BOOL ("words-include-escapes", &words_include_escapes /*
1689 Non-nil means `forward-word', etc., should treat escape chars part of words.
1690 */ );
1691   words_include_escapes = 0;
1692
1693   no_quit_in_re_search = 0;
1694 }
1695
1696 static void
1697 define_standard_syntax (const char *p, enum syntaxcode syn)
1698 {
1699   for (; *p; p++)
1700     Fput_char_table (make_char (*p), make_int (syn), Vstandard_syntax_table);
1701 }
1702
1703 void
1704 complex_vars_of_syntax (void)
1705 {
1706   Emchar i;
1707   const char *p;
1708   /* Set this now, so first buffer creation can refer to it. */
1709   /* Make it nil before calling copy-syntax-table
1710      so that copy-syntax-table will know not to try to copy from garbage */
1711   Vstandard_syntax_table = Qnil;
1712   Vstandard_syntax_table = Fcopy_syntax_table (Qnil);
1713   staticpro (&Vstandard_syntax_table);
1714
1715   Vsyntax_designator_chars_string = make_string_nocopy (syntax_code_spec,
1716                                                         Smax);
1717   staticpro (&Vsyntax_designator_chars_string);
1718
1719   fill_char_table (XCHAR_TABLE (Vstandard_syntax_table), make_int (Spunct));
1720
1721   for (i = 0; i <= 32; i++)     /* Control 0 plus SPACE */
1722     Fput_char_table (make_char (i), make_int (Swhitespace),
1723                      Vstandard_syntax_table);
1724   for (i = 127; i <= 159; i++)  /* DEL plus Control 1 */
1725     Fput_char_table (make_char (i), make_int (Swhitespace),
1726                      Vstandard_syntax_table);
1727
1728   define_standard_syntax ("abcdefghijklmnopqrstuvwxyz"
1729                           "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1730                           "0123456789"
1731                           "$%", Sword);
1732   define_standard_syntax ("\"", Sstring);
1733   define_standard_syntax ("\\", Sescape);
1734   define_standard_syntax ("_-+*/&|<>=", Ssymbol);
1735   define_standard_syntax (".,;:?!#@~^'`", Spunct);
1736
1737   for (p = "()[]{}"; *p; p+=2)
1738     {
1739       Fput_char_table (make_char (p[0]),
1740                        Fcons (make_int (Sopen), make_char (p[1])),
1741                        Vstandard_syntax_table);
1742       Fput_char_table (make_char (p[1]),
1743                        Fcons (make_int (Sclose), make_char (p[0])),
1744                        Vstandard_syntax_table);
1745     }
1746 }