(combine-run-hooks): New function.
[emacs.git] / src / syntax.c
blob167e20ebed5ee524a07cd9c3867b0499eb321e49
1 /* GNU Emacs routines to deal with syntax tables; also word and list parsing.
2 Copyright (C) 1985, 87, 93, 94, 95, 97, 1998, 1999 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
22 #include <config.h>
23 #include <ctype.h>
24 #include "lisp.h"
25 #include "commands.h"
26 #include "buffer.h"
27 #include "charset.h"
29 /* Make syntax table lookup grant data in gl_state. */
30 #define SYNTAX_ENTRY_VIA_PROPERTY
32 #include "syntax.h"
33 #include "intervals.h"
35 /* We use these constants in place for comment-style and
36 string-ender-char to distinguish comments/strings started by
37 comment_fence and string_fence codes. */
39 #define ST_COMMENT_STYLE (256 + 1)
40 #define ST_STRING_STYLE (256 + 2)
41 #include "category.h"
43 Lisp_Object Qsyntax_table_p, Qsyntax_table, Qscan_error;
45 int words_include_escapes;
46 int parse_sexp_lookup_properties;
48 /* Nonzero means `scan-sexps' treat all multibyte characters as symbol. */
49 int multibyte_syntax_as_symbol;
51 /* Used as a temporary in SYNTAX_ENTRY and other macros in syntax.h,
52 if not compiled with GCC. No need to mark it, since it is used
53 only very temporarily. */
54 Lisp_Object syntax_temp;
56 /* This is the internal form of the parse state used in parse-partial-sexp. */
58 struct lisp_parse_state
60 int depth; /* Depth at end of parsing. */
61 int instring; /* -1 if not within string, else desired terminator. */
62 int incomment; /* -1 if in unnestable comment else comment nesting */
63 int comstyle; /* comment style a=0, or b=1, or ST_COMMENT_STYLE. */
64 int quoted; /* Nonzero if just after an escape char at end of parsing */
65 int thislevelstart; /* Char number of most recent start-of-expression at current level */
66 int prevlevelstart; /* Char number of start of containing expression */
67 int location; /* Char number at which parsing stopped. */
68 int mindepth; /* Minimum depth seen while scanning. */
69 int comstr_start; /* Position just after last comment/string starter. */
70 Lisp_Object levelstarts; /* Char numbers of starts-of-expression
71 of levels (starting from outermost). */
74 /* These variables are a cache for finding the start of a defun.
75 find_start_pos is the place for which the defun start was found.
76 find_start_value is the defun start position found for it.
77 find_start_value_byte is the corresponding byte position.
78 find_start_buffer is the buffer it was found in.
79 find_start_begv is the BEGV value when it was found.
80 find_start_modiff is the value of MODIFF when it was found. */
82 static int find_start_pos;
83 static int find_start_value;
84 static int find_start_value_byte;
85 static struct buffer *find_start_buffer;
86 static int find_start_begv;
87 static int find_start_modiff;
90 static int find_defun_start P_ ((int, int));
91 static int back_comment P_ ((int, int, int, int, int, int *, int *));
92 static int char_quoted P_ ((int, int));
93 static Lisp_Object skip_chars P_ ((int, int, Lisp_Object, Lisp_Object));
94 static Lisp_Object scan_lists P_ ((int, int, int, int));
95 static void scan_sexps_forward P_ ((struct lisp_parse_state *,
96 int, int, int, int,
97 int, Lisp_Object, int));
100 struct gl_state_s gl_state; /* Global state of syntax parser. */
102 INTERVAL interval_of ();
103 #define INTERVALS_AT_ONCE 10 /* 1 + max-number of intervals
104 to scan to property-change. */
106 /* Update gl_state to an appropriate interval which contains CHARPOS. The
107 sign of COUNT give the relative position of CHARPOS wrt the previously
108 valid interval. If INIT, only [be]_property fields of gl_state are
109 valid at start, the rest is filled basing on OBJECT.
111 `gl_state.*_i' are the intervals, and CHARPOS is further in the search
112 direction than the intervals - or in an interval. We update the
113 current syntax-table basing on the property of this interval, and
114 update the interval to start further than CHARPOS - or be
115 NULL_INTERVAL. We also update lim_property to be the next value of
116 charpos to call this subroutine again - or be before/after the
117 start/end of OBJECT. */
119 void
120 update_syntax_table (charpos, count, init, object)
121 int charpos, count, init;
122 Lisp_Object object;
124 Lisp_Object tmp_table;
125 int cnt = 0, invalidate = 1;
126 INTERVAL i, oldi;
128 if (init)
130 gl_state.start = gl_state.b_property;
131 gl_state.stop = gl_state.e_property;
132 gl_state.forward_i = interval_of (charpos, object);
133 i = gl_state.backward_i = gl_state.forward_i;
134 gl_state.left_ok = gl_state.right_ok = 1;
135 invalidate = 0;
136 if (NULL_INTERVAL_P (i))
137 return;
138 /* interval_of updates only ->position of the return value, so
139 update the parents manually to speed up update_interval. */
140 while (!NULL_PARENT (i))
142 if (AM_RIGHT_CHILD (i))
143 i->parent->position = i->position
144 - LEFT_TOTAL_LENGTH (i) + TOTAL_LENGTH (i) /* right end */
145 - TOTAL_LENGTH (i->parent)
146 + LEFT_TOTAL_LENGTH (i->parent);
147 else
148 i->parent->position = i->position - LEFT_TOTAL_LENGTH (i)
149 + TOTAL_LENGTH (i);
150 i = i->parent;
152 i = gl_state.forward_i;
153 gl_state.b_property = i->position - 1 - gl_state.offset;
154 gl_state.e_property = INTERVAL_LAST_POS (i) - gl_state.offset;
155 goto update;
157 oldi = i = count > 0 ? gl_state.forward_i : gl_state.backward_i;
159 /* We are guarantied to be called with CHARPOS either in i,
160 or further off. */
161 if (NULL_INTERVAL_P (i))
162 error ("Error in syntax_table logic for to-the-end intervals");
163 else if (charpos < i->position) /* Move left. */
165 if (count > 0)
166 error ("Error in syntax_table logic for intervals <-");
167 /* Update the interval. */
168 i = update_interval (i, charpos);
169 if (oldi->position != INTERVAL_LAST_POS (i))
171 invalidate = 0;
172 gl_state.right_ok = 1; /* Invalidate the other end. */
173 gl_state.forward_i = i;
174 gl_state.e_property = INTERVAL_LAST_POS (i) - gl_state.offset;
177 else if (charpos >= INTERVAL_LAST_POS (i)) /* Move right. */
179 if (count < 0)
180 error ("Error in syntax_table logic for intervals ->");
181 /* Update the interval. */
182 i = update_interval (i, charpos);
183 if (i->position != INTERVAL_LAST_POS (oldi))
185 invalidate = 0;
186 gl_state.left_ok = 1; /* Invalidate the other end. */
187 gl_state.backward_i = i;
188 gl_state.b_property = i->position - 1 - gl_state.offset;
191 else if (count > 0 ? gl_state.right_ok : gl_state.left_ok)
193 /* We do not need to recalculate tmp_table. */
194 tmp_table = gl_state.old_prop;
197 update:
198 tmp_table = textget (i->plist, Qsyntax_table);
200 if (invalidate)
201 invalidate = !EQ (tmp_table, gl_state.old_prop); /* Need to invalidate? */
203 if (invalidate) /* Did not get to adjacent interval. */
204 { /* with the same table => */
205 /* invalidate the old range. */
206 if (count > 0)
208 gl_state.backward_i = i;
209 gl_state.left_ok = 1; /* Invalidate the other end. */
210 gl_state.b_property = i->position - 1 - gl_state.offset;
212 else
214 gl_state.forward_i = i;
215 gl_state.right_ok = 1; /* Invalidate the other end. */
216 gl_state.e_property = INTERVAL_LAST_POS (i) - gl_state.offset;
220 gl_state.current_syntax_table = tmp_table;
221 gl_state.old_prop = tmp_table;
222 if (EQ (Fsyntax_table_p (tmp_table), Qt))
224 gl_state.use_global = 0;
226 else if (CONSP (tmp_table))
228 gl_state.use_global = 1;
229 gl_state.global_code = tmp_table;
231 else
233 gl_state.use_global = 0;
234 gl_state.current_syntax_table = current_buffer->syntax_table;
237 while (!NULL_INTERVAL_P (i))
239 if (cnt && !EQ (tmp_table, textget (i->plist, Qsyntax_table)))
241 if (count > 0)
242 gl_state.right_ok = 0;
243 else
244 gl_state.left_ok = 0;
245 break;
247 else if (cnt == INTERVALS_AT_ONCE)
249 if (count > 0)
250 gl_state.right_ok = 1;
251 else
252 gl_state.left_ok = 1;
253 break;
255 cnt++;
256 i = count > 0 ? next_interval (i) : previous_interval (i);
258 if (NULL_INTERVAL_P (i))
259 { /* This property goes to the end. */
260 if (count > 0)
261 gl_state.e_property = gl_state.stop;
262 else
263 gl_state.b_property = gl_state.start;
265 else
267 if (count > 0)
269 gl_state.e_property = i->position - gl_state.offset;
270 gl_state.forward_i = i;
272 else
274 gl_state.b_property = i->position + LENGTH (i) - 1 - gl_state.offset;
275 gl_state.backward_i = i;
280 /* Returns TRUE if char at CHARPOS is quoted.
281 Global syntax-table data should be set up already to be good at CHARPOS
282 or after. On return global syntax data is good for lookup at CHARPOS. */
284 static int
285 char_quoted (charpos, bytepos)
286 register int charpos, bytepos;
288 register enum syntaxcode code;
289 register int beg = BEGV;
290 register int quoted = 0;
291 int orig = charpos;
293 DEC_BOTH (charpos, bytepos);
295 while (bytepos >= beg)
297 UPDATE_SYNTAX_TABLE_BACKWARD (charpos);
298 code = SYNTAX (FETCH_CHAR (bytepos));
299 if (! (code == Scharquote || code == Sescape))
300 break;
302 DEC_BOTH (charpos, bytepos);
303 quoted = !quoted;
306 UPDATE_SYNTAX_TABLE (orig);
307 return quoted;
310 /* Return the bytepos one character after BYTEPOS.
311 We assume that BYTEPOS is not at the end of the buffer. */
313 INLINE int
314 inc_bytepos (bytepos)
315 int bytepos;
317 if (NILP (current_buffer->enable_multibyte_characters))
318 return bytepos + 1;
320 INC_POS (bytepos);
321 return bytepos;
324 /* Return the bytepos one character before BYTEPOS.
325 We assume that BYTEPOS is not at the start of the buffer. */
327 INLINE int
328 dec_bytepos (bytepos)
329 int bytepos;
331 if (NILP (current_buffer->enable_multibyte_characters))
332 return bytepos - 1;
334 DEC_POS (bytepos);
335 return bytepos;
338 /* Find a defun-start that is the last one before POS (or nearly the last).
339 We record what we find, so that another call in the same area
340 can return the same value right away.
342 There is no promise at which position the global syntax data is
343 valid on return from the subroutine, so the caller should explicitly
344 update the global data. */
346 static int
347 find_defun_start (pos, pos_byte)
348 int pos, pos_byte;
350 int opoint = PT, opoint_byte = PT_BYTE;
352 /* Use previous finding, if it's valid and applies to this inquiry. */
353 if (current_buffer == find_start_buffer
354 /* Reuse the defun-start even if POS is a little farther on.
355 POS might be in the next defun, but that's ok.
356 Our value may not be the best possible, but will still be usable. */
357 && pos <= find_start_pos + 1000
358 && pos >= find_start_value
359 && BEGV == find_start_begv
360 && MODIFF == find_start_modiff)
361 return find_start_value;
363 /* Back up to start of line. */
364 scan_newline (pos, pos_byte, BEGV, BEGV_BYTE, -1, 1);
366 /* We optimize syntax-table lookup for rare updates. Thus we accept
367 only those `^\s(' which are good in global _and_ text-property
368 syntax-tables. */
369 gl_state.current_syntax_table = current_buffer->syntax_table;
370 gl_state.use_global = 0;
371 while (PT > BEGV)
373 /* Open-paren at start of line means we found our defun-start. */
374 if (SYNTAX (FETCH_CHAR (PT_BYTE)) == Sopen)
376 SETUP_SYNTAX_TABLE (PT + 1, -1); /* Try again... */
377 if (SYNTAX (FETCH_CHAR (PT_BYTE)) == Sopen)
378 break;
379 /* Now fallback to the default value. */
380 gl_state.current_syntax_table = current_buffer->syntax_table;
381 gl_state.use_global = 0;
383 /* Move to beg of previous line. */
384 scan_newline (PT, PT_BYTE, BEGV, BEGV_BYTE, -2, 1);
387 /* Record what we found, for the next try. */
388 find_start_value = PT;
389 find_start_value_byte = PT_BYTE;
390 find_start_buffer = current_buffer;
391 find_start_modiff = MODIFF;
392 find_start_begv = BEGV;
393 find_start_pos = pos;
395 TEMP_SET_PT_BOTH (opoint, opoint_byte);
397 return find_start_value;
400 /* Return the SYNTAX_COMEND_FIRST of the character before POS, POS_BYTE. */
402 static int
403 prev_char_comend_first (pos, pos_byte)
404 int pos, pos_byte;
406 int c, val;
408 DEC_BOTH (pos, pos_byte);
409 UPDATE_SYNTAX_TABLE_BACKWARD (pos);
410 c = FETCH_CHAR (pos_byte);
411 val = SYNTAX_COMEND_FIRST (c);
412 UPDATE_SYNTAX_TABLE_FORWARD (pos + 1);
413 return val;
416 /* Return the SYNTAX_COMSTART_FIRST of the character before POS, POS_BYTE. */
418 static int
419 prev_char_comstart_first (pos, pos_byte)
420 int pos, pos_byte;
422 int c, val;
424 DEC_BOTH (pos, pos_byte);
425 UPDATE_SYNTAX_TABLE_BACKWARD (pos);
426 c = FETCH_CHAR (pos_byte);
427 val = SYNTAX_COMSTART_FIRST (c);
428 UPDATE_SYNTAX_TABLE_FORWARD (pos + 1);
429 return val;
432 /* Checks whether charpos FROM is at the end of a comment.
433 FROM_BYTE is the bytepos corresponding to FROM.
434 Do not move back before STOP.
436 Return a positive value if we find a comment ending at FROM/FROM_BYTE;
437 return -1 otherwise.
439 If successful, store the charpos of the comment's beginning
440 into *CHARPOS_PTR, and the bytepos into *BYTEPOS_PTR.
442 Global syntax data remains valid for backward search starting at
443 the returned value (or at FROM, if the search was not successful). */
445 static int
446 back_comment (from, from_byte, stop, comnested, comstyle, charpos_ptr, bytepos_ptr)
447 int from, from_byte, stop;
448 int comnested, comstyle;
449 int *charpos_ptr, *bytepos_ptr;
451 /* Look back, counting the parity of string-quotes,
452 and recording the comment-starters seen.
453 When we reach a safe place, assume that's not in a string;
454 then step the main scan to the earliest comment-starter seen
455 an even number of string quotes away from the safe place.
457 OFROM[I] is position of the earliest comment-starter seen
458 which is I+2X quotes from the comment-end.
459 PARITY is current parity of quotes from the comment end. */
460 int parity = 0;
461 int my_stringend = 0;
462 int string_lossage = 0;
463 int comment_end = from;
464 int comment_end_byte = from_byte;
465 int comstart_pos = 0;
466 int comstart_byte;
467 /* Value that PARITY had, when we reached the position
468 in COMSTART_POS. */
469 int comstart_parity = 0;
470 int scanstart = from - 1;
471 /* Place where the containing defun starts,
472 or 0 if we didn't come across it yet. */
473 int defun_start = 0;
474 int defun_start_byte = 0;
475 register enum syntaxcode code;
476 int nesting = 1; /* current comment nesting */
477 int c;
479 /* At beginning of range to scan, we're outside of strings;
480 that determines quote parity to the comment-end. */
481 while (from != stop)
483 int temp_byte;
485 /* Move back and examine a character. */
486 DEC_BOTH (from, from_byte);
487 UPDATE_SYNTAX_TABLE_BACKWARD (from);
489 c = FETCH_CHAR (from_byte);
490 code = SYNTAX (c);
492 /* If this char is the second of a 2-char comment end sequence,
493 back up and give the pair the appropriate syntax. */
494 if (from > stop && SYNTAX_COMEND_SECOND (c)
495 && prev_char_comend_first (from, from_byte))
497 code = Sendcomment;
498 DEC_BOTH (from, from_byte);
499 UPDATE_SYNTAX_TABLE_BACKWARD (from);
500 c = FETCH_CHAR (from_byte);
503 /* If this char starts a 2-char comment start sequence,
504 treat it like a 1-char comment starter. */
505 if (from < scanstart && SYNTAX_COMSTART_FIRST (c))
507 temp_byte = inc_bytepos (from_byte);
508 UPDATE_SYNTAX_TABLE_FORWARD (from + 1);
509 if (SYNTAX_COMSTART_SECOND (FETCH_CHAR (temp_byte))
510 && comstyle == SYNTAX_COMMENT_STYLE (FETCH_CHAR (temp_byte)))
511 code = Scomment;
512 UPDATE_SYNTAX_TABLE_BACKWARD (from);
514 else if (code == Scomment && comstyle != SYNTAX_COMMENT_STYLE (c))
515 /* Ignore comment starters of a different style. */
516 continue;
518 /* Ignore escaped characters, except comment-enders. */
519 if (code != Sendcomment && char_quoted (from, from_byte))
520 continue;
522 /* Track parity of quotes. */
523 if (code == Sstring)
525 parity ^= 1;
526 if (my_stringend == 0)
527 my_stringend = c;
528 /* If we have two kinds of string delimiters.
529 There's no way to grok this scanning backwards. */
530 else if (my_stringend != c)
531 string_lossage = 1;
534 if (code == Sstring_fence || code == Scomment_fence)
536 parity ^= 1;
537 if (my_stringend == 0)
538 my_stringend
539 = code == Sstring_fence ? ST_STRING_STYLE : ST_COMMENT_STYLE;
540 /* If we have two kinds of string delimiters.
541 There's no way to grok this scanning backwards. */
542 else if (my_stringend != (code == Sstring_fence
543 ? ST_STRING_STYLE : ST_COMMENT_STYLE))
544 string_lossage = 1;
547 if (code == Scomment)
548 /* We've already checked that it is the relevant comstyle. */
550 if (comnested && --nesting <= 0 && parity == 0 && !string_lossage)
551 /* nested comments have to be balanced, so we don't need to
552 keep looking for earlier ones. We use here the same (slightly
553 incorrect) reasoning as below: since it is followed by uniform
554 paired string quotes, this comment-start has to be outside of
555 strings, else the comment-end itself would be inside a string. */
556 goto done;
558 /* Record comment-starters according to that
559 quote-parity to the comment-end. */
560 comstart_parity = parity;
561 comstart_pos = from;
562 comstart_byte = from_byte;
565 /* If we find another earlier comment-ender,
566 any comment-starts earlier than that don't count
567 (because they go with the earlier comment-ender). */
568 if (code == Sendcomment
569 && SYNTAX_COMMENT_STYLE (FETCH_CHAR (from_byte)) == comstyle)
571 if (comnested)
572 nesting++;
573 else
574 break;
577 /* Assume a defun-start point is outside of strings. */
578 if (code == Sopen
579 && (from == stop
580 || (temp_byte = dec_bytepos (from_byte),
581 FETCH_CHAR (temp_byte) == '\n')))
583 defun_start = from;
584 defun_start_byte = from_byte;
585 break;
589 if (comstart_pos == 0)
591 from = comment_end;
592 from_byte = comment_end_byte;
593 UPDATE_SYNTAX_TABLE_FORWARD (comment_end - 1);
595 /* If the earliest comment starter
596 is followed by uniform paired string quotes or none,
597 we know it can't be inside a string
598 since if it were then the comment ender would be inside one.
599 So it does start a comment. Skip back to it. */
600 else if (!comnested && comstart_parity == 0 && !string_lossage)
602 from = comstart_pos;
603 from_byte = comstart_byte;
604 /* Globals are correct now. */
606 else
608 /* We had two kinds of string delimiters mixed up
609 together. Decode this going forwards.
610 Scan fwd from the previous comment ender
611 to the one in question; this records where we
612 last passed a comment starter. */
613 struct lisp_parse_state state;
614 /* If we did not already find the defun start, find it now. */
615 if (defun_start == 0)
617 defun_start = find_defun_start (comment_end, comment_end_byte);
618 defun_start_byte = find_start_value_byte;
620 scan_sexps_forward (&state,
621 defun_start, defun_start_byte,
622 comment_end - 1, -10000, 0, Qnil, 0);
623 if (state.incomment)
625 /* scan_sexps_forward changed the direction of search in
626 global variables, so we need to update it completely. */
628 from = state.comstr_start;
630 else
632 from = comment_end;
634 from_byte = CHAR_TO_BYTE (from);
635 UPDATE_SYNTAX_TABLE_FORWARD (from - 1);
638 done:
639 *charpos_ptr = from;
640 *bytepos_ptr = from_byte;
642 return (from == comment_end) ? -1 : from;
645 DEFUN ("syntax-table-p", Fsyntax_table_p, Ssyntax_table_p, 1, 1, 0,
646 "Return t if OBJECT is a syntax table.\n\
647 Currently, any char-table counts as a syntax table.")
648 (object)
649 Lisp_Object object;
651 if (CHAR_TABLE_P (object)
652 && EQ (XCHAR_TABLE (object)->purpose, Qsyntax_table))
653 return Qt;
654 return Qnil;
657 static void
658 check_syntax_table (obj)
659 Lisp_Object obj;
661 if (!(CHAR_TABLE_P (obj)
662 && EQ (XCHAR_TABLE (obj)->purpose, Qsyntax_table)))
663 wrong_type_argument (Qsyntax_table_p, obj);
666 DEFUN ("syntax-table", Fsyntax_table, Ssyntax_table, 0, 0, 0,
667 "Return the current syntax table.\n\
668 This is the one specified by the current buffer.")
671 return current_buffer->syntax_table;
674 DEFUN ("standard-syntax-table", Fstandard_syntax_table,
675 Sstandard_syntax_table, 0, 0, 0,
676 "Return the standard syntax table.\n\
677 This is the one used for new buffers.")
680 return Vstandard_syntax_table;
683 DEFUN ("copy-syntax-table", Fcopy_syntax_table, Scopy_syntax_table, 0, 1, 0,
684 "Construct a new syntax table and return it.\n\
685 It is a copy of the TABLE, which defaults to the standard syntax table.")
686 (table)
687 Lisp_Object table;
689 Lisp_Object copy;
691 if (!NILP (table))
692 check_syntax_table (table);
693 else
694 table = Vstandard_syntax_table;
696 copy = Fcopy_sequence (table);
698 /* Only the standard syntax table should have a default element.
699 Other syntax tables should inherit from parents instead. */
700 XCHAR_TABLE (copy)->defalt = Qnil;
702 /* Copied syntax tables should all have parents.
703 If we copied one with no parent, such as the standard syntax table,
704 use the standard syntax table as the copy's parent. */
705 if (NILP (XCHAR_TABLE (copy)->parent))
706 Fset_char_table_parent (copy, Vstandard_syntax_table);
707 return copy;
710 DEFUN ("set-syntax-table", Fset_syntax_table, Sset_syntax_table, 1, 1, 0,
711 "Select a new syntax table for the current buffer.\n\
712 One argument, a syntax table.")
713 (table)
714 Lisp_Object table;
716 check_syntax_table (table);
717 current_buffer->syntax_table = table;
718 /* Indicate that this buffer now has a specified syntax table. */
719 current_buffer->local_var_flags
720 |= XFASTINT (buffer_local_flags.syntax_table);
721 return table;
724 /* Convert a letter which signifies a syntax code
725 into the code it signifies.
726 This is used by modify-syntax-entry, and other things. */
728 unsigned char syntax_spec_code[0400] =
729 { 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377,
730 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377,
731 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377,
732 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377,
733 (char) Swhitespace, (char) Scomment_fence, (char) Sstring, 0377,
734 (char) Smath, 0377, 0377, (char) Squote,
735 (char) Sopen, (char) Sclose, 0377, 0377,
736 0377, (char) Swhitespace, (char) Spunct, (char) Scharquote,
737 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377,
738 0377, 0377, 0377, 0377,
739 (char) Scomment, 0377, (char) Sendcomment, 0377,
740 (char) Sinherit, 0377, 0377, 0377, 0377, 0377, 0377, 0377, /* @, A ... */
741 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377,
742 0377, 0377, 0377, 0377, 0377, 0377, 0377, (char) Sword,
743 0377, 0377, 0377, 0377, (char) Sescape, 0377, 0377, (char) Ssymbol,
744 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, /* `, a, ... */
745 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377,
746 0377, 0377, 0377, 0377, 0377, 0377, 0377, (char) Sword,
747 0377, 0377, 0377, 0377, (char) Sstring_fence, 0377, 0377, 0377
750 /* Indexed by syntax code, give the letter that describes it. */
752 char syntax_code_spec[16] =
754 ' ', '.', 'w', '_', '(', ')', '\'', '\"', '$', '\\', '/', '<', '>', '@',
755 '!', '|'
758 /* Indexed by syntax code, give the object (cons of syntax code and
759 nil) to be stored in syntax table. Since these objects can be
760 shared among syntax tables, we generate them in advance. By
761 sharing objects, the function `describe-syntax' can give a more
762 compact listing. */
763 static Lisp_Object Vsyntax_code_object;
766 /* Look up the value for CHARACTER in syntax table TABLE's parent
767 and its parents. SYNTAX_ENTRY calls this, when TABLE itself has nil
768 for CHARACTER. It's actually used only when not compiled with GCC. */
770 Lisp_Object
771 syntax_parent_lookup (table, character)
772 Lisp_Object table;
773 int character;
775 Lisp_Object value;
777 while (1)
779 table = XCHAR_TABLE (table)->parent;
780 if (NILP (table))
781 return Qnil;
783 value = XCHAR_TABLE (table)->contents[character];
784 if (!NILP (value))
785 return value;
789 DEFUN ("char-syntax", Fchar_syntax, Schar_syntax, 1, 1, 0,
790 "Return the syntax code of CHARACTER, described by a character.\n\
791 For example, if CHARACTER is a word constituent,\n\
792 the character `w' is returned.\n\
793 The characters that correspond to various syntax codes\n\
794 are listed in the documentation of `modify-syntax-entry'.")
795 (character)
796 Lisp_Object character;
798 int char_int;
799 gl_state.current_syntax_table = current_buffer->syntax_table;
801 gl_state.use_global = 0;
802 CHECK_NUMBER (character, 0);
803 char_int = XINT (character);
804 return make_number (syntax_code_spec[(int) SYNTAX (char_int)]);
807 DEFUN ("matching-paren", Fmatching_paren, Smatching_paren, 1, 1, 0,
808 "Return the matching parenthesis of CHARACTER, or nil if none.")
809 (character)
810 Lisp_Object character;
812 int char_int, code;
813 gl_state.current_syntax_table = current_buffer->syntax_table;
814 gl_state.use_global = 0;
815 CHECK_NUMBER (character, 0);
816 char_int = XINT (character);
817 code = SYNTAX (char_int);
818 if (code == Sopen || code == Sclose)
819 return SYNTAX_MATCH (char_int);
820 return Qnil;
823 /* This comment supplies the doc string for modify-syntax-entry,
824 for make-docfile to see. We cannot put this in the real DEFUN
825 due to limits in the Unix cpp.
827 DEFUN ("modify-syntax-entry", foo, bar, 2, 3, 0,
828 "Set syntax for character CHAR according to string S.\n\
829 The syntax is changed only for table TABLE, which defaults to\n\
830 the current buffer's syntax table.\n\
831 The first character of S should be one of the following:\n\
832 Space or - whitespace syntax. w word constituent.\n\
833 _ symbol constituent. . punctuation.\n\
834 ( open-parenthesis. ) close-parenthesis.\n\
835 \" string quote. \\ escape.\n\
836 $ paired delimiter. ' expression quote or prefix operator.\n\
837 < comment starter. > comment ender.\n\
838 / character-quote. @ inherit from `standard-syntax-table'.\n\
840 Only single-character comment start and end sequences are represented thus.\n\
841 Two-character sequences are represented as described below.\n\
842 The second character of S is the matching parenthesis,\n\
843 used only if the first character is `(' or `)'.\n\
844 Any additional characters are flags.\n\
845 Defined flags are the characters 1, 2, 3, 4, b, p, and n.\n\
846 1 means CHAR is the start of a two-char comment start sequence.\n\
847 2 means CHAR is the second character of such a sequence.\n\
848 3 means CHAR is the start of a two-char comment end sequence.\n\
849 4 means CHAR is the second character of such a sequence.\n\
851 There can be up to two orthogonal comment sequences. This is to support\n\
852 language modes such as C++. By default, all comment sequences are of style\n\
853 a, but you can set the comment sequence style to b (on the second character\n\
854 of a comment-start, or the first character of a comment-end sequence) using\n\
855 this flag:\n\
856 b means CHAR is part of comment sequence b.\n\
857 n means CHAR is part of a nestable comment sequence.\n\
859 p means CHAR is a prefix character for `backward-prefix-chars';\n\
860 such characters are treated as whitespace when they occur\n\
861 between expressions.")
862 (char, s, table)
865 DEFUN ("modify-syntax-entry", Fmodify_syntax_entry, Smodify_syntax_entry, 2, 3,
866 /* I really don't know why this is interactive
867 help-form should at least be made useful whilst reading the second arg
869 "cSet syntax for character: \nsSet syntax for %s to: ",
870 0 /* See immediately above */)
871 (c, newentry, syntax_table)
872 Lisp_Object c, newentry, syntax_table;
874 register unsigned char *p;
875 register enum syntaxcode code;
876 int val;
877 Lisp_Object match;
879 CHECK_NUMBER (c, 0);
880 CHECK_STRING (newentry, 1);
882 if (NILP (syntax_table))
883 syntax_table = current_buffer->syntax_table;
884 else
885 check_syntax_table (syntax_table);
887 p = XSTRING (newentry)->data;
888 code = (enum syntaxcode) syntax_spec_code[*p++];
889 if (((int) code & 0377) == 0377)
890 error ("invalid syntax description letter: %c", p[-1]);
892 if (code == Sinherit)
894 SET_RAW_SYNTAX_ENTRY (syntax_table, XINT (c), Qnil);
895 return Qnil;
898 if (*p)
900 int len;
901 int character = (STRING_CHAR_AND_LENGTH
902 (p, STRING_BYTES (XSTRING (newentry)) - 1, len));
903 XSETINT (match, character);
904 if (XFASTINT (match) == ' ')
905 match = Qnil;
906 p += len;
908 else
909 match = Qnil;
911 val = (int) code;
912 while (*p)
913 switch (*p++)
915 case '1':
916 val |= 1 << 16;
917 break;
919 case '2':
920 val |= 1 << 17;
921 break;
923 case '3':
924 val |= 1 << 18;
925 break;
927 case '4':
928 val |= 1 << 19;
929 break;
931 case 'p':
932 val |= 1 << 20;
933 break;
935 case 'b':
936 val |= 1 << 21;
937 break;
939 case 'n':
940 val |= 1 << 22;
941 break;
944 if (val < XVECTOR (Vsyntax_code_object)->size && NILP (match))
945 newentry = XVECTOR (Vsyntax_code_object)->contents[val];
946 else
947 /* Since we can't use a shared object, let's make a new one. */
948 newentry = Fcons (make_number (val), match);
950 SET_RAW_SYNTAX_ENTRY (syntax_table, XINT (c), newentry);
952 return Qnil;
955 /* Dump syntax table to buffer in human-readable format */
957 static void
958 describe_syntax (value)
959 Lisp_Object value;
961 register enum syntaxcode code;
962 char desc, start1, start2, end1, end2, prefix, comstyle;
963 char str[2];
964 Lisp_Object first, match_lisp;
966 Findent_to (make_number (16), make_number (1));
968 if (NILP (value))
970 insert_string ("default\n");
971 return;
974 if (CHAR_TABLE_P (value))
976 insert_string ("deeper char-table ...\n");
977 return;
980 if (!CONSP (value))
982 insert_string ("invalid\n");
983 return;
986 first = XCAR (value);
987 match_lisp = XCDR (value);
989 if (!INTEGERP (first) || !(NILP (match_lisp) || INTEGERP (match_lisp)))
991 insert_string ("invalid\n");
992 return;
995 code = (enum syntaxcode) (XINT (first) & 0377);
996 start1 = (XINT (first) >> 16) & 1;
997 start2 = (XINT (first) >> 17) & 1;
998 end1 = (XINT (first) >> 18) & 1;
999 end2 = (XINT (first) >> 19) & 1;
1000 prefix = (XINT (first) >> 20) & 1;
1001 comstyle = (XINT (first) >> 21) & 1;
1003 if ((int) code < 0 || (int) code >= (int) Smax)
1005 insert_string ("invalid");
1006 return;
1008 desc = syntax_code_spec[(int) code];
1010 str[0] = desc, str[1] = 0;
1011 insert (str, 1);
1013 if (NILP (match_lisp))
1014 insert (" ", 1);
1015 else
1016 insert_char (XINT (match_lisp));
1018 if (start1)
1019 insert ("1", 1);
1020 if (start2)
1021 insert ("2", 1);
1023 if (end1)
1024 insert ("3", 1);
1025 if (end2)
1026 insert ("4", 1);
1028 if (prefix)
1029 insert ("p", 1);
1030 if (comstyle)
1031 insert ("b", 1);
1033 insert_string ("\twhich means: ");
1035 switch (SWITCH_ENUM_CAST (code))
1037 case Swhitespace:
1038 insert_string ("whitespace"); break;
1039 case Spunct:
1040 insert_string ("punctuation"); break;
1041 case Sword:
1042 insert_string ("word"); break;
1043 case Ssymbol:
1044 insert_string ("symbol"); break;
1045 case Sopen:
1046 insert_string ("open"); break;
1047 case Sclose:
1048 insert_string ("close"); break;
1049 case Squote:
1050 insert_string ("quote"); break;
1051 case Sstring:
1052 insert_string ("string"); break;
1053 case Smath:
1054 insert_string ("math"); break;
1055 case Sescape:
1056 insert_string ("escape"); break;
1057 case Scharquote:
1058 insert_string ("charquote"); break;
1059 case Scomment:
1060 insert_string ("comment"); break;
1061 case Sendcomment:
1062 insert_string ("endcomment"); break;
1063 default:
1064 insert_string ("invalid");
1065 return;
1068 if (!NILP (match_lisp))
1070 insert_string (", matches ");
1071 insert_char (XINT (match_lisp));
1074 if (start1)
1075 insert_string (",\n\t is the first character of a comment-start sequence");
1076 if (start2)
1077 insert_string (",\n\t is the second character of a comment-start sequence");
1079 if (end1)
1080 insert_string (",\n\t is the first character of a comment-end sequence");
1081 if (end2)
1082 insert_string (",\n\t is the second character of a comment-end sequence");
1083 if (comstyle)
1084 insert_string (" (comment style b)");
1086 if (prefix)
1087 insert_string (",\n\t is a prefix character for `backward-prefix-chars'");
1089 insert_string ("\n");
1092 static Lisp_Object
1093 describe_syntax_1 (vector)
1094 Lisp_Object vector;
1096 struct buffer *old = current_buffer;
1097 set_buffer_internal (XBUFFER (Vstandard_output));
1098 describe_vector (vector, Qnil, describe_syntax, 0, Qnil, Qnil, (int *) 0, 0);
1099 while (! NILP (XCHAR_TABLE (vector)->parent))
1101 vector = XCHAR_TABLE (vector)->parent;
1102 insert_string ("\nThe parent syntax table is:");
1103 describe_vector (vector, Qnil, describe_syntax, 0, Qnil, Qnil,
1104 (int *) 0, 0);
1107 call0 (intern ("help-mode"));
1108 set_buffer_internal (old);
1109 return Qnil;
1112 DEFUN ("describe-syntax", Fdescribe_syntax, Sdescribe_syntax, 0, 0, "",
1113 "Describe the syntax specifications in the syntax table.\n\
1114 The descriptions are inserted in a buffer, which is then displayed.")
1117 internal_with_output_to_temp_buffer
1118 ("*Help*", describe_syntax_1, current_buffer->syntax_table);
1120 return Qnil;
1123 int parse_sexp_ignore_comments;
1125 /* Return the position across COUNT words from FROM.
1126 If that many words cannot be found before the end of the buffer, return 0.
1127 COUNT negative means scan backward and stop at word beginning. */
1130 scan_words (from, count)
1131 register int from, count;
1133 register int beg = BEGV;
1134 register int end = ZV;
1135 register int from_byte = CHAR_TO_BYTE (from);
1136 register enum syntaxcode code;
1137 int ch0, ch1;
1139 immediate_quit = 1;
1140 QUIT;
1142 SETUP_SYNTAX_TABLE (from, count);
1144 while (count > 0)
1146 while (1)
1148 if (from == end)
1150 immediate_quit = 0;
1151 return 0;
1153 UPDATE_SYNTAX_TABLE_FORWARD (from);
1154 ch0 = FETCH_CHAR (from_byte);
1155 code = SYNTAX (ch0);
1156 INC_BOTH (from, from_byte);
1157 if (words_include_escapes
1158 && (code == Sescape || code == Scharquote))
1159 break;
1160 if (code == Sword)
1161 break;
1163 /* Now CH0 is a character which begins a word and FROM is the
1164 position of the next character. */
1165 while (1)
1167 if (from == end) break;
1168 UPDATE_SYNTAX_TABLE_FORWARD (from);
1169 ch1 = FETCH_CHAR (from_byte);
1170 code = SYNTAX (ch1);
1171 if (!(words_include_escapes
1172 && (code == Sescape || code == Scharquote)))
1173 if (code != Sword || WORD_BOUNDARY_P (ch0, ch1))
1174 break;
1175 INC_BOTH (from, from_byte);
1176 ch0 = ch1;
1178 count--;
1180 while (count < 0)
1182 while (1)
1184 if (from == beg)
1186 immediate_quit = 0;
1187 return 0;
1189 DEC_BOTH (from, from_byte);
1190 UPDATE_SYNTAX_TABLE_BACKWARD (from);
1191 ch1 = FETCH_CHAR (from_byte);
1192 code = SYNTAX (ch1);
1193 if (words_include_escapes
1194 && (code == Sescape || code == Scharquote))
1195 break;
1196 if (code == Sword)
1197 break;
1199 /* Now CH1 is a character which ends a word and FROM is the
1200 position of it. */
1201 while (1)
1203 int temp_byte;
1205 if (from == beg)
1206 break;
1207 temp_byte = dec_bytepos (from_byte);
1208 UPDATE_SYNTAX_TABLE_BACKWARD (from);
1209 ch0 = FETCH_CHAR (temp_byte);
1210 code = SYNTAX (ch0);
1211 if (!(words_include_escapes
1212 && (code == Sescape || code == Scharquote)))
1213 if (code != Sword || WORD_BOUNDARY_P (ch0, ch1))
1214 break;
1215 DEC_BOTH (from, from_byte);
1216 ch1 = ch0;
1218 count++;
1221 immediate_quit = 0;
1223 return from;
1226 DEFUN ("forward-word", Fforward_word, Sforward_word, 1, 1, "p",
1227 "Move point forward ARG words (backward if ARG is negative).\n\
1228 Normally returns t.\n\
1229 If an edge of the buffer or a field boundary is reached, point is left there\n\
1230 and the function returns nil. Field boundaries are not noticed if\n\
1231 `inhibit-field-text-motion' is non-nil.")
1232 (count)
1233 Lisp_Object count;
1235 int orig_val, val;
1236 CHECK_NUMBER (count, 0);
1238 val = orig_val = scan_words (PT, XINT (count));
1239 if (! orig_val)
1240 val = XINT (count) > 0 ? ZV : BEGV;
1242 /* Avoid jumping out of an input field. */
1243 val = XFASTINT (Fconstrain_to_field (make_number (val), make_number (PT),
1244 Qt, Qnil));
1246 SET_PT (val);
1247 return val == orig_val ? Qt : Qnil;
1250 Lisp_Object skip_chars ();
1252 DEFUN ("skip-chars-forward", Fskip_chars_forward, Sskip_chars_forward, 1, 2, 0,
1253 "Move point forward, stopping before a char not in STRING, or at pos LIM.\n\
1254 STRING is like the inside of a `[...]' in a regular expression\n\
1255 except that `]' is never special and `\\' quotes `^', `-' or `\\'\n\
1256 (but not as the end of a range; quoting is never needed there).\n\
1257 Thus, with arg \"a-zA-Z\", this skips letters stopping before first nonletter.\n\
1258 With arg \"^a-zA-Z\", skips nonletters stopping before first letter.\n\
1259 Returns the distance traveled, either zero or positive.")
1260 (string, lim)
1261 Lisp_Object string, lim;
1263 return skip_chars (1, 0, string, lim);
1266 DEFUN ("skip-chars-backward", Fskip_chars_backward, Sskip_chars_backward, 1, 2, 0,
1267 "Move point backward, stopping after a char not in STRING, or at pos LIM.\n\
1268 See `skip-chars-forward' for details.\n\
1269 Returns the distance traveled, either zero or negative.")
1270 (string, lim)
1271 Lisp_Object string, lim;
1273 return skip_chars (0, 0, string, lim);
1276 DEFUN ("skip-syntax-forward", Fskip_syntax_forward, Sskip_syntax_forward, 1, 2, 0,
1277 "Move point forward across chars in specified syntax classes.\n\
1278 SYNTAX is a string of syntax code characters.\n\
1279 Stop before a char whose syntax is not in SYNTAX, or at position LIM.\n\
1280 If SYNTAX starts with ^, skip characters whose syntax is NOT in SYNTAX.\n\
1281 This function returns the distance traveled, either zero or positive.")
1282 (syntax, lim)
1283 Lisp_Object syntax, lim;
1285 return skip_chars (1, 1, syntax, lim);
1288 DEFUN ("skip-syntax-backward", Fskip_syntax_backward, Sskip_syntax_backward, 1, 2, 0,
1289 "Move point backward across chars in specified syntax classes.\n\
1290 SYNTAX is a string of syntax code characters.\n\
1291 Stop on reaching a char whose syntax is not in SYNTAX, or at position LIM.\n\
1292 If SYNTAX starts with ^, skip characters whose syntax is NOT in SYNTAX.\n\
1293 This function returns the distance traveled, either zero or negative.")
1294 (syntax, lim)
1295 Lisp_Object syntax, lim;
1297 return skip_chars (0, 1, syntax, lim);
1300 static Lisp_Object
1301 skip_chars (forwardp, syntaxp, string, lim)
1302 int forwardp, syntaxp;
1303 Lisp_Object string, lim;
1305 register unsigned int c;
1306 register int ch;
1307 unsigned char fastmap[0400];
1308 /* If SYNTAXP is 0, STRING may contain multi-byte form of characters
1309 of which codes don't fit in FASTMAP. In that case, we set the
1310 first byte of multibyte form (i.e. base leading-code) in FASTMAP
1311 and set the actual ranges of characters in CHAR_RANGES. In the
1312 form "X-Y" of STRING, both X and Y must belong to the same
1313 character set because a range striding across character sets is
1314 meaningless. */
1315 int *char_ranges;
1316 int n_char_ranges = 0;
1317 int negate = 0;
1318 register int i, i_byte;
1319 int multibyte = !NILP (current_buffer->enable_multibyte_characters);
1320 int string_multibyte;
1321 int size_byte;
1323 CHECK_STRING (string, 0);
1324 char_ranges = (int *) alloca (XSTRING (string)->size * (sizeof (int)) * 2);
1325 string_multibyte = STRING_MULTIBYTE (string);
1326 size_byte = STRING_BYTES (XSTRING (string));
1328 if (NILP (lim))
1329 XSETINT (lim, forwardp ? ZV : BEGV);
1330 else
1331 CHECK_NUMBER_COERCE_MARKER (lim, 0);
1333 /* In any case, don't allow scan outside bounds of buffer. */
1334 if (XINT (lim) > ZV)
1335 XSETFASTINT (lim, ZV);
1336 if (XINT (lim) < BEGV)
1337 XSETFASTINT (lim, BEGV);
1339 bzero (fastmap, sizeof fastmap);
1341 i = 0, i_byte = 0;
1343 if (i_byte < size_byte
1344 && XSTRING (string)->data[0] == '^')
1346 negate = 1; i++, i_byte++;
1349 /* Find the characters specified and set their elements of fastmap.
1350 If syntaxp, each character counts as itself.
1351 Otherwise, handle backslashes and ranges specially. */
1353 while (i_byte < size_byte)
1355 int c_leading_code;
1357 if (string_multibyte)
1359 c_leading_code = XSTRING (string)->data[i_byte];
1360 FETCH_STRING_CHAR_ADVANCE (c, string, i, i_byte);
1362 else
1363 c = c_leading_code = XSTRING (string)->data[i_byte++];
1365 /* Convert multibyteness between what the string has
1366 and what the buffer has. */
1367 if (multibyte)
1368 c = unibyte_char_to_multibyte (c);
1369 else
1370 c &= 0377;
1372 if (syntaxp)
1373 fastmap[syntax_spec_code[c & 0377]] = 1;
1374 else
1376 if (c == '\\')
1378 if (i_byte == size_byte)
1379 break;
1381 if (string_multibyte)
1383 c_leading_code = XSTRING (string)->data[i_byte];
1384 FETCH_STRING_CHAR_ADVANCE (c, string, i, i_byte);
1386 else
1387 c = c_leading_code = XSTRING (string)->data[i_byte++];
1389 if (i_byte < size_byte
1390 && XSTRING (string)->data[i_byte] == '-')
1392 unsigned int c2, c2_leading_code;
1394 /* Skip over the dash. */
1395 i++, i_byte++;
1397 if (i_byte == size_byte)
1398 break;
1400 /* Get the end of the range. */
1401 if (string_multibyte)
1403 c2_leading_code = XSTRING (string)->data[i_byte];
1404 FETCH_STRING_CHAR_ADVANCE (c2, string, i, i_byte);
1406 else
1407 c2 = XSTRING (string)->data[i_byte++];
1409 if (SINGLE_BYTE_CHAR_P (c))
1411 if (! SINGLE_BYTE_CHAR_P (c2))
1412 error ("Invalid charcter range: %s",
1413 XSTRING (string)->data);
1414 while (c <= c2)
1416 fastmap[c] = 1;
1417 c++;
1420 else
1422 if (c_leading_code != c2_leading_code)
1423 error ("Invalid charcter range: %s",
1424 XSTRING (string)->data);
1425 fastmap[c_leading_code] = 1;
1426 if (c <= c2)
1428 char_ranges[n_char_ranges++] = c;
1429 char_ranges[n_char_ranges++] = c2;
1433 else
1435 fastmap[c_leading_code] = 1;
1436 if (!SINGLE_BYTE_CHAR_P (c))
1438 char_ranges[n_char_ranges++] = c;
1439 char_ranges[n_char_ranges++] = c;
1445 /* If ^ was the first character, complement the fastmap. In
1446 addition, as all multibyte characters have possibility of
1447 matching, set all entries for base leading codes, which is
1448 harmless even if SYNTAXP is 1. */
1450 if (negate)
1451 for (i = 0; i < sizeof fastmap; i++)
1453 if (!multibyte || !BASE_LEADING_CODE_P (i))
1454 fastmap[i] ^= 1;
1455 else
1456 fastmap[i] = 1;
1460 int start_point = PT;
1461 int pos = PT;
1462 int pos_byte = PT_BYTE;
1464 immediate_quit = 1;
1465 if (syntaxp)
1467 SETUP_SYNTAX_TABLE (pos, forwardp ? 1 : -1);
1468 if (forwardp)
1470 if (multibyte)
1472 if (pos < XINT (lim))
1473 while (fastmap[(int) SYNTAX (FETCH_CHAR (pos_byte))])
1475 /* Since we already checked for multibyteness,
1476 avoid using INC_BOTH which checks again. */
1477 INC_POS (pos_byte);
1478 pos++;
1479 if (pos >= XINT (lim))
1480 break;
1481 UPDATE_SYNTAX_TABLE_FORWARD (pos);
1484 else
1486 while (pos < XINT (lim)
1487 && fastmap[(int) SYNTAX (FETCH_BYTE (pos))])
1489 pos++;
1490 UPDATE_SYNTAX_TABLE_FORWARD (pos);
1494 else
1496 if (multibyte)
1498 while (pos > XINT (lim))
1500 int savepos = pos_byte;
1501 /* Since we already checked for multibyteness,
1502 avoid using DEC_BOTH which checks again. */
1503 pos--;
1504 DEC_POS (pos_byte);
1505 UPDATE_SYNTAX_TABLE_BACKWARD (pos);
1506 if (!fastmap[(int) SYNTAX (FETCH_CHAR (pos_byte))])
1508 pos++;
1509 pos_byte = savepos;
1510 break;
1514 else
1516 if (pos > XINT (lim))
1517 while (fastmap[(int) SYNTAX (FETCH_BYTE (pos - 1))])
1519 pos--;
1520 if (pos <= XINT (lim))
1521 break;
1522 UPDATE_SYNTAX_TABLE_BACKWARD (pos - 1);
1527 else
1529 if (forwardp)
1531 if (multibyte)
1532 while (pos < XINT (lim) && fastmap[(c = FETCH_BYTE (pos_byte))])
1534 if (!BASE_LEADING_CODE_P (c))
1535 INC_BOTH (pos, pos_byte);
1536 else if (n_char_ranges)
1538 /* We much check CHAR_RANGES for a multibyte
1539 character. */
1540 ch = FETCH_MULTIBYTE_CHAR (pos_byte);
1541 for (i = 0; i < n_char_ranges; i += 2)
1542 if ((ch >= char_ranges[i] && ch <= char_ranges[i + 1]))
1543 break;
1544 if (!(negate ^ (i < n_char_ranges)))
1545 break;
1547 INC_BOTH (pos, pos_byte);
1549 else
1551 if (!negate) break;
1552 INC_BOTH (pos, pos_byte);
1555 else
1556 while (pos < XINT (lim) && fastmap[FETCH_BYTE (pos)])
1557 pos++;
1559 else
1561 if (multibyte)
1562 while (pos > XINT (lim))
1564 int savepos = pos_byte;
1565 DEC_BOTH (pos, pos_byte);
1566 if (fastmap[(c = FETCH_BYTE (pos_byte))])
1568 if (!BASE_LEADING_CODE_P (c))
1570 else if (n_char_ranges)
1572 /* We much check CHAR_RANGES for a multibyte
1573 character. */
1574 ch = FETCH_MULTIBYTE_CHAR (pos_byte);
1575 for (i = 0; i < n_char_ranges; i += 2)
1576 if (ch >= char_ranges[i] && ch <= char_ranges[i + 1])
1577 break;
1578 if (!(negate ^ (i < n_char_ranges)))
1580 pos++;
1581 pos_byte = savepos;
1582 break;
1585 else
1586 if (!negate)
1588 pos++;
1589 pos_byte = savepos;
1590 break;
1593 else
1595 pos++;
1596 pos_byte = savepos;
1597 break;
1600 else
1601 while (pos > XINT (lim) && fastmap[FETCH_BYTE (pos - 1)])
1602 pos--;
1606 #if 0 /* Not needed now that a position in mid-character
1607 cannot be specified in Lisp. */
1608 if (multibyte
1609 /* INC_POS or DEC_POS might have moved POS over LIM. */
1610 && (forwardp ? (pos > XINT (lim)) : (pos < XINT (lim))))
1611 pos = XINT (lim);
1612 #endif
1614 if (! multibyte)
1615 pos_byte = pos;
1617 SET_PT_BOTH (pos, pos_byte);
1618 immediate_quit = 0;
1620 return make_number (PT - start_point);
1624 /* Jump over a comment, assuming we are at the beginning of one.
1625 FROM is the current position.
1626 FROM_BYTE is the bytepos corresponding to FROM.
1627 Do not move past STOP (a charpos).
1628 The comment over which we have to jump is of style STYLE
1629 (either SYNTAX_COMMENT_STYLE(foo) or ST_COMMENT_STYLE).
1630 NESTING should be positive to indicate the nesting at the beginning
1631 for nested comments and should be zero or negative else.
1632 ST_COMMENT_STYLE cannot be nested.
1633 PREV_SYNTAX is the SYNTAX_WITH_FLAGS of the previous character
1634 (or 0 If the search cannot start in the middle of a two-character).
1636 If successful, return 1 and store the charpos of the comment's end
1637 into *CHARPOS_PTR and the corresponding bytepos into *BYTEPOS_PTR.
1638 Else, return 0 and store the charpos STOP into *CHARPOS_PTR, the
1639 corresponding bytepos into *BYTEPOS_PTR and the current nesting
1640 (as defined for state.incomment) in *INCOMMENT_PTR.
1642 The comment end is the last character of the comment rather than the
1643 character just after the comment.
1645 Global syntax data is assumed to initially be valid for FROM and
1646 remains valid for forward search starting at the returned position. */
1648 static int
1649 forw_comment (from, from_byte, stop, nesting, style, prev_syntax,
1650 charpos_ptr, bytepos_ptr, incomment_ptr)
1651 int from, from_byte, stop;
1652 int nesting, style, prev_syntax;
1653 int *charpos_ptr, *bytepos_ptr, *incomment_ptr;
1655 register int c, c1;
1656 register enum syntaxcode code;
1657 register int syntax;
1659 if (nesting <= 0) nesting = -1;
1661 /* Enter the loop in the middle so that we find
1662 a 2-char comment ender if we start in the middle of it. */
1663 syntax = prev_syntax;
1664 if (syntax != 0) goto forw_incomment;
1666 while (1)
1668 if (from == stop)
1670 *incomment_ptr = nesting;
1671 *charpos_ptr = from;
1672 *bytepos_ptr = from_byte;
1673 return 0;
1675 c = FETCH_CHAR (from_byte);
1676 syntax = SYNTAX_WITH_FLAGS (c);
1677 code = syntax & 0xff;
1678 if (code == Sendcomment
1679 && SYNTAX_FLAGS_COMMENT_STYLE (syntax) == style
1680 && --nesting <= 0)
1681 /* we have encountered a comment end of the same style
1682 as the comment sequence which began this comment
1683 section */
1684 break;
1685 if (code == Scomment_fence
1686 && style == ST_COMMENT_STYLE)
1687 /* we have encountered a comment end of the same style
1688 as the comment sequence which began this comment
1689 section. */
1690 break;
1691 if (nesting > 0
1692 && code == Scomment
1693 && SYNTAX_FLAGS_COMMENT_STYLE (syntax) == style)
1694 /* we have encountered a nested comment of the same style
1695 as the comment sequence which began this comment section */
1696 nesting++;
1697 INC_BOTH (from, from_byte);
1698 UPDATE_SYNTAX_TABLE_FORWARD (from);
1700 forw_incomment:
1701 if (from < stop && SYNTAX_FLAGS_COMEND_FIRST (syntax)
1702 && SYNTAX_FLAGS_COMMENT_STYLE (syntax) == style
1703 && (c1 = FETCH_CHAR (from_byte),
1704 SYNTAX_COMEND_SECOND (c1)))
1706 if (--nesting <= 0)
1707 /* we have encountered a comment end of the same style
1708 as the comment sequence which began this comment
1709 section */
1710 break;
1711 else
1713 INC_BOTH (from, from_byte);
1714 UPDATE_SYNTAX_TABLE_FORWARD (from);
1717 if (nesting > 0
1718 && from < stop
1719 && SYNTAX_FLAGS_COMSTART_FIRST (syntax)
1720 && (c1 = FETCH_CHAR (from_byte),
1721 SYNTAX_COMMENT_STYLE (c1) == style
1722 && SYNTAX_COMSTART_SECOND (c1)))
1723 /* we have encountered a nested comment of the same style
1724 as the comment sequence which began this comment
1725 section */
1727 INC_BOTH (from, from_byte);
1728 UPDATE_SYNTAX_TABLE_FORWARD (from);
1729 nesting++;
1732 *charpos_ptr = from;
1733 *bytepos_ptr = from_byte;
1734 return 1;
1737 DEFUN ("forward-comment", Fforward_comment, Sforward_comment, 1, 1, 0,
1738 "Move forward across up to N comments. If N is negative, move backward.\n\
1739 Stop scanning if we find something other than a comment or whitespace.\n\
1740 Set point to where scanning stops.\n\
1741 If N comments are found as expected, with nothing except whitespace\n\
1742 between them, return t; otherwise return nil.")
1743 (count)
1744 Lisp_Object count;
1746 register int from;
1747 int from_byte;
1748 register int stop;
1749 register int c, c1;
1750 register enum syntaxcode code;
1751 int comstyle = 0; /* style of comment encountered */
1752 int comnested = 0; /* whether the comment is nestable or not */
1753 int found;
1754 int count1;
1755 int out_charpos, out_bytepos;
1756 int dummy;
1758 CHECK_NUMBER (count, 0);
1759 count1 = XINT (count);
1760 stop = count1 > 0 ? ZV : BEGV;
1762 immediate_quit = 1;
1763 QUIT;
1765 from = PT;
1766 from_byte = PT_BYTE;
1768 SETUP_SYNTAX_TABLE (from, count1);
1769 while (count1 > 0)
1773 int comstart_first;
1775 if (from == stop)
1777 SET_PT_BOTH (from, from_byte);
1778 immediate_quit = 0;
1779 return Qnil;
1781 c = FETCH_CHAR (from_byte);
1782 code = SYNTAX (c);
1783 comstart_first = SYNTAX_COMSTART_FIRST (c);
1784 comnested = SYNTAX_COMMENT_NESTED (c);
1785 INC_BOTH (from, from_byte);
1786 UPDATE_SYNTAX_TABLE_FORWARD (from);
1787 comstyle = 0;
1788 if (from < stop && comstart_first
1789 && (c1 = FETCH_CHAR (from_byte),
1790 SYNTAX_COMSTART_SECOND (c1)))
1792 /* We have encountered a comment start sequence and we
1793 are ignoring all text inside comments. We must record
1794 the comment style this sequence begins so that later,
1795 only a comment end of the same style actually ends
1796 the comment section. */
1797 code = Scomment;
1798 comstyle = SYNTAX_COMMENT_STYLE (c1);
1799 comnested = comnested || SYNTAX_COMMENT_NESTED (c1);
1800 INC_BOTH (from, from_byte);
1801 UPDATE_SYNTAX_TABLE_FORWARD (from);
1803 /* FIXME: here we ignore 2-char endcomments while we don't
1804 when going backwards. */
1806 while (code == Swhitespace || code == Sendcomment);
1808 if (code == Scomment_fence)
1809 comstyle = ST_COMMENT_STYLE;
1810 else if (code != Scomment)
1812 immediate_quit = 0;
1813 DEC_BOTH (from, from_byte);
1814 SET_PT_BOTH (from, from_byte);
1815 return Qnil;
1817 /* We're at the start of a comment. */
1818 found = forw_comment (from, from_byte, stop, comnested, comstyle, 0,
1819 &out_charpos, &out_bytepos, &dummy);
1820 from = out_charpos; from_byte = out_bytepos;
1821 if (!found)
1823 immediate_quit = 0;
1824 SET_PT_BOTH (from, from_byte);
1825 return Qnil;
1827 INC_BOTH (from, from_byte);
1828 UPDATE_SYNTAX_TABLE_FORWARD (from);
1829 /* We have skipped one comment. */
1830 count1--;
1833 while (count1 < 0)
1835 while (1)
1837 int quoted, comstart_second;
1839 if (from <= stop)
1841 SET_PT_BOTH (BEGV, BEGV_BYTE);
1842 immediate_quit = 0;
1843 return Qnil;
1846 DEC_BOTH (from, from_byte);
1847 /* char_quoted does UPDATE_SYNTAX_TABLE_BACKWARD (from). */
1848 quoted = char_quoted (from, from_byte);
1849 if (quoted)
1851 DEC_BOTH (from, from_byte);
1852 goto leave;
1854 c = FETCH_CHAR (from_byte);
1855 code = SYNTAX (c);
1856 comstyle = 0;
1857 comnested = SYNTAX_COMMENT_NESTED (c);
1858 if (code == Sendcomment)
1859 comstyle = SYNTAX_COMMENT_STYLE (c);
1860 comstart_second = SYNTAX_COMSTART_SECOND (c);
1861 if (from > stop && SYNTAX_COMEND_SECOND (c)
1862 && prev_char_comend_first (from, from_byte)
1863 && !char_quoted (from - 1, dec_bytepos (from_byte)))
1865 /* We must record the comment style encountered so that
1866 later, we can match only the proper comment begin
1867 sequence of the same style. */
1868 DEC_BOTH (from, from_byte);
1869 code = Sendcomment;
1870 /* Calling char_quoted, above, set up global syntax position
1871 at the new value of FROM. */
1872 c1 = FETCH_CHAR (from_byte);
1873 comstyle = SYNTAX_COMMENT_STYLE (c1);
1874 comnested = comnested || SYNTAX_COMMENT_NESTED (c1);
1876 if (from > stop && comstart_second
1877 && prev_char_comstart_first (from, from_byte)
1878 && !char_quoted (from - 1, dec_bytepos (from_byte)))
1880 code = Scomment;
1881 DEC_BOTH (from, from_byte);
1884 if (code == Scomment_fence)
1886 /* Skip until first preceding unquoted comment_fence. */
1887 int found = 0, ini = from, ini_byte = from_byte;
1889 while (1)
1891 DEC_BOTH (from, from_byte);
1892 if (from == stop)
1893 break;
1894 UPDATE_SYNTAX_TABLE_BACKWARD (from);
1895 c = FETCH_CHAR (from_byte);
1896 if (SYNTAX (c) == Scomment_fence
1897 && !char_quoted (from, from_byte))
1899 found = 1;
1900 break;
1903 if (found == 0)
1905 from = ini; /* Set point to ini + 1. */
1906 from_byte = ini_byte;
1907 goto leave;
1910 else if (code == Sendcomment)
1912 found = back_comment (from, from_byte, stop, comnested, comstyle,
1913 &out_charpos, &out_bytepos);
1914 if (found == -1)
1916 #if 0 /* cc-mode (and maybe others) relies on the bogus behavior. */
1917 /* Failure: we should go back to the end of this
1918 not-quite-endcomment. */
1919 if (SYNTAX(c) != code)
1920 /* It was a two-char Sendcomment. */
1921 INC_BOTH (from, from_byte);
1922 goto leave;
1923 #endif
1925 else
1926 /* We have skipped one comment. */
1927 from = out_charpos, from_byte = out_bytepos;
1928 break;
1930 else if (code != Swhitespace && code != Scomment)
1932 leave:
1933 immediate_quit = 0;
1934 INC_BOTH (from, from_byte);
1935 SET_PT_BOTH (from, from_byte);
1936 return Qnil;
1940 count1++;
1943 SET_PT_BOTH (from, from_byte);
1944 immediate_quit = 0;
1945 return Qt;
1948 /* Return syntax code of character C if C is a single byte character
1949 or `multibyte_symbol_p' is zero. Otherwise, retrun Ssymbol. */
1951 #define SYNTAX_WITH_MULTIBYTE_CHECK(c) \
1952 ((SINGLE_BYTE_CHAR_P (c) || !multibyte_symbol_p) \
1953 ? SYNTAX (c) : Ssymbol)
1955 static Lisp_Object
1956 scan_lists (from, count, depth, sexpflag)
1957 register int from;
1958 int count, depth, sexpflag;
1960 Lisp_Object val;
1961 register int stop = count > 0 ? ZV : BEGV;
1962 register int c, c1;
1963 int stringterm;
1964 int quoted;
1965 int mathexit = 0;
1966 register enum syntaxcode code, temp_code;
1967 int min_depth = depth; /* Err out if depth gets less than this. */
1968 int comstyle = 0; /* style of comment encountered */
1969 int comnested = 0; /* whether the comment is nestable or not */
1970 int temp_pos;
1971 int last_good = from;
1972 int found;
1973 int from_byte;
1974 int out_bytepos, out_charpos;
1975 int temp, dummy;
1976 int multibyte_symbol_p = sexpflag && multibyte_syntax_as_symbol;
1978 if (depth > 0) min_depth = 0;
1980 if (from > ZV) from = ZV;
1981 if (from < BEGV) from = BEGV;
1983 from_byte = CHAR_TO_BYTE (from);
1985 immediate_quit = 1;
1986 QUIT;
1988 SETUP_SYNTAX_TABLE (from, count);
1989 while (count > 0)
1991 while (from < stop)
1993 int comstart_first, prefix;
1994 UPDATE_SYNTAX_TABLE_FORWARD (from);
1995 c = FETCH_CHAR (from_byte);
1996 code = SYNTAX_WITH_MULTIBYTE_CHECK (c);
1997 comstart_first = SYNTAX_COMSTART_FIRST (c);
1998 comnested = SYNTAX_COMMENT_NESTED (c);
1999 prefix = SYNTAX_PREFIX (c);
2000 if (depth == min_depth)
2001 last_good = from;
2002 INC_BOTH (from, from_byte);
2003 UPDATE_SYNTAX_TABLE_FORWARD (from);
2004 if (from < stop && comstart_first
2005 && SYNTAX_COMSTART_SECOND (FETCH_CHAR (from_byte))
2006 && parse_sexp_ignore_comments)
2008 /* we have encountered a comment start sequence and we
2009 are ignoring all text inside comments. We must record
2010 the comment style this sequence begins so that later,
2011 only a comment end of the same style actually ends
2012 the comment section */
2013 code = Scomment;
2014 c1 = FETCH_CHAR (from_byte);
2015 comstyle = SYNTAX_COMMENT_STYLE (c1);
2016 comnested = comnested || SYNTAX_COMMENT_NESTED (c1);
2017 INC_BOTH (from, from_byte);
2018 UPDATE_SYNTAX_TABLE_FORWARD (from);
2021 if (prefix)
2022 continue;
2024 switch (SWITCH_ENUM_CAST (code))
2026 case Sescape:
2027 case Scharquote:
2028 if (from == stop) goto lose;
2029 INC_BOTH (from, from_byte);
2030 /* treat following character as a word constituent */
2031 case Sword:
2032 case Ssymbol:
2033 if (depth || !sexpflag) break;
2034 /* This word counts as a sexp; return at end of it. */
2035 while (from < stop)
2037 UPDATE_SYNTAX_TABLE_FORWARD (from);
2039 /* Some compilers can't handle this inside the switch. */
2040 c = FETCH_CHAR (from_byte);
2041 temp = SYNTAX_WITH_MULTIBYTE_CHECK (c);
2042 switch (temp)
2044 case Scharquote:
2045 case Sescape:
2046 INC_BOTH (from, from_byte);
2047 if (from == stop) goto lose;
2048 break;
2049 case Sword:
2050 case Ssymbol:
2051 case Squote:
2052 break;
2053 default:
2054 goto done;
2056 INC_BOTH (from, from_byte);
2058 goto done;
2060 case Scomment_fence:
2061 comstyle = ST_COMMENT_STYLE;
2062 /* FALLTHROUGH */
2063 case Scomment:
2064 if (!parse_sexp_ignore_comments) break;
2065 UPDATE_SYNTAX_TABLE_FORWARD (from);
2066 found = forw_comment (from, from_byte, stop,
2067 comnested, comstyle, 0,
2068 &out_charpos, &out_bytepos, &dummy);
2069 from = out_charpos, from_byte = out_bytepos;
2070 if (!found)
2072 if (depth == 0)
2073 goto done;
2074 goto lose;
2076 INC_BOTH (from, from_byte);
2077 UPDATE_SYNTAX_TABLE_FORWARD (from);
2078 break;
2080 case Smath:
2081 if (!sexpflag)
2082 break;
2083 if (from != stop && c == FETCH_CHAR (from_byte))
2085 INC_BOTH (from, from_byte);
2087 if (mathexit)
2089 mathexit = 0;
2090 goto close1;
2092 mathexit = 1;
2094 case Sopen:
2095 if (!++depth) goto done;
2096 break;
2098 case Sclose:
2099 close1:
2100 if (!--depth) goto done;
2101 if (depth < min_depth)
2102 Fsignal (Qscan_error,
2103 Fcons (build_string ("Containing expression ends prematurely"),
2104 Fcons (make_number (last_good),
2105 Fcons (make_number (from), Qnil))));
2106 break;
2108 case Sstring:
2109 case Sstring_fence:
2110 temp_pos = dec_bytepos (from_byte);
2111 stringterm = FETCH_CHAR (temp_pos);
2112 while (1)
2114 if (from >= stop) goto lose;
2115 UPDATE_SYNTAX_TABLE_FORWARD (from);
2116 c = FETCH_CHAR (from_byte);
2117 if (code == Sstring
2118 ? c == stringterm
2119 : SYNTAX_WITH_MULTIBYTE_CHECK (c) == Sstring_fence)
2120 break;
2122 /* Some compilers can't handle this inside the switch. */
2123 temp = SYNTAX_WITH_MULTIBYTE_CHECK (c);
2124 switch (temp)
2126 case Scharquote:
2127 case Sescape:
2128 INC_BOTH (from, from_byte);
2130 INC_BOTH (from, from_byte);
2132 INC_BOTH (from, from_byte);
2133 if (!depth && sexpflag) goto done;
2134 break;
2138 /* Reached end of buffer. Error if within object, return nil if between */
2139 if (depth) goto lose;
2141 immediate_quit = 0;
2142 return Qnil;
2144 /* End of object reached */
2145 done:
2146 count--;
2149 while (count < 0)
2151 while (from > stop)
2153 DEC_BOTH (from, from_byte);
2154 UPDATE_SYNTAX_TABLE_BACKWARD (from);
2155 c = FETCH_CHAR (from_byte);
2156 code = SYNTAX_WITH_MULTIBYTE_CHECK (c);
2157 if (depth == min_depth)
2158 last_good = from;
2159 comstyle = 0;
2160 comnested = SYNTAX_COMMENT_NESTED (c);
2161 if (code == Sendcomment)
2162 comstyle = SYNTAX_COMMENT_STYLE (c);
2163 if (from > stop && SYNTAX_COMEND_SECOND (c)
2164 && prev_char_comend_first (from, from_byte)
2165 && parse_sexp_ignore_comments)
2167 /* We must record the comment style encountered so that
2168 later, we can match only the proper comment begin
2169 sequence of the same style. */
2170 DEC_BOTH (from, from_byte);
2171 UPDATE_SYNTAX_TABLE_BACKWARD (from);
2172 code = Sendcomment;
2173 c1 = FETCH_CHAR (from_byte);
2174 comstyle = SYNTAX_COMMENT_STYLE (c1);
2175 comnested = comnested || SYNTAX_COMMENT_NESTED (c1);
2178 /* Quoting turns anything except a comment-ender
2179 into a word character. Note that this if cannot be true
2180 if we decremented FROM in the if-statement above. */
2181 if (code != Sendcomment && char_quoted (from, from_byte))
2182 code = Sword;
2183 else if (SYNTAX_PREFIX (c))
2184 continue;
2186 switch (SWITCH_ENUM_CAST (code))
2188 case Sword:
2189 case Ssymbol:
2190 case Sescape:
2191 case Scharquote:
2192 if (depth || !sexpflag) break;
2193 /* This word counts as a sexp; count object finished
2194 after passing it. */
2195 while (from > stop)
2197 temp_pos = from_byte;
2198 if (! NILP (current_buffer->enable_multibyte_characters))
2199 DEC_POS (temp_pos);
2200 else
2201 temp_pos--;
2202 UPDATE_SYNTAX_TABLE_BACKWARD (from - 1);
2203 c1 = FETCH_CHAR (temp_pos);
2204 temp_code = SYNTAX_WITH_MULTIBYTE_CHECK (c1);
2205 /* Don't allow comment-end to be quoted. */
2206 if (temp_code == Sendcomment)
2207 goto done2;
2208 quoted = char_quoted (from - 1, temp_pos);
2209 if (quoted)
2211 DEC_BOTH (from, from_byte);
2212 temp_pos = dec_bytepos (temp_pos);
2213 UPDATE_SYNTAX_TABLE_BACKWARD (from - 1);
2215 c1 = FETCH_CHAR (temp_pos);
2216 temp_code = SYNTAX_WITH_MULTIBYTE_CHECK (c1);
2217 if (! (quoted || temp_code == Sword
2218 || temp_code == Ssymbol
2219 || temp_code == Squote))
2220 goto done2;
2221 DEC_BOTH (from, from_byte);
2223 goto done2;
2225 case Smath:
2226 if (!sexpflag)
2227 break;
2228 temp_pos = dec_bytepos (from_byte);
2229 UPDATE_SYNTAX_TABLE_BACKWARD (from - 1);
2230 if (from != stop && c == FETCH_CHAR (temp_pos))
2231 DEC_BOTH (from, from_byte);
2232 if (mathexit)
2234 mathexit = 0;
2235 goto open2;
2237 mathexit = 1;
2239 case Sclose:
2240 if (!++depth) goto done2;
2241 break;
2243 case Sopen:
2244 open2:
2245 if (!--depth) goto done2;
2246 if (depth < min_depth)
2247 Fsignal (Qscan_error,
2248 Fcons (build_string ("Containing expression ends prematurely"),
2249 Fcons (make_number (last_good),
2250 Fcons (make_number (from), Qnil))));
2251 break;
2253 case Sendcomment:
2254 if (!parse_sexp_ignore_comments)
2255 break;
2256 found = back_comment (from, from_byte, stop, comnested, comstyle,
2257 &out_charpos, &out_bytepos);
2258 /* FIXME: if found == -1, then it really wasn't a comment-end.
2259 For single-char Sendcomment, we can't do much about it apart
2260 from skipping the char.
2261 For 2-char endcomments, we could try again, taking both
2262 chars as separate entities, but it's a lot of trouble
2263 for very little gain, so we don't bother either. -sm */
2264 if (found != -1)
2265 from = out_charpos, from_byte = out_bytepos;
2266 break;
2268 case Scomment_fence:
2269 case Sstring_fence:
2270 while (1)
2272 DEC_BOTH (from, from_byte);
2273 if (from == stop) goto lose;
2274 UPDATE_SYNTAX_TABLE_BACKWARD (from);
2275 if (!char_quoted (from, from_byte)
2276 && (c = FETCH_CHAR (from_byte),
2277 SYNTAX_WITH_MULTIBYTE_CHECK (c) == code))
2278 break;
2280 if (code == Sstring_fence && !depth && sexpflag) goto done2;
2281 break;
2283 case Sstring:
2284 stringterm = FETCH_CHAR (from_byte);
2285 while (1)
2287 if (from == stop) goto lose;
2288 temp_pos = from_byte;
2289 if (! NILP (current_buffer->enable_multibyte_characters))
2290 DEC_POS (temp_pos);
2291 else
2292 temp_pos--;
2293 UPDATE_SYNTAX_TABLE_BACKWARD (from - 1);
2294 if (!char_quoted (from - 1, temp_pos)
2295 && stringterm == FETCH_CHAR (temp_pos))
2296 break;
2297 DEC_BOTH (from, from_byte);
2299 DEC_BOTH (from, from_byte);
2300 if (!depth && sexpflag) goto done2;
2301 break;
2305 /* Reached start of buffer. Error if within object, return nil if between */
2306 if (depth) goto lose;
2308 immediate_quit = 0;
2309 return Qnil;
2311 done2:
2312 count++;
2316 immediate_quit = 0;
2317 XSETFASTINT (val, from);
2318 return val;
2320 lose:
2321 Fsignal (Qscan_error,
2322 Fcons (build_string ("Unbalanced parentheses"),
2323 Fcons (make_number (last_good),
2324 Fcons (make_number (from), Qnil))));
2326 /* NOTREACHED */
2329 DEFUN ("scan-lists", Fscan_lists, Sscan_lists, 3, 3, 0,
2330 "Scan from character number FROM by COUNT lists.\n\
2331 Returns the character number of the position thus found.\n\
2333 If DEPTH is nonzero, paren depth begins counting from that value,\n\
2334 only places where the depth in parentheses becomes zero\n\
2335 are candidates for stopping; COUNT such places are counted.\n\
2336 Thus, a positive value for DEPTH means go out levels.\n\
2338 Comments are ignored if `parse-sexp-ignore-comments' is non-nil.\n\
2340 If the beginning or end of (the accessible part of) the buffer is reached\n\
2341 and the depth is wrong, an error is signaled.\n\
2342 If the depth is right but the count is not used up, nil is returned.")
2343 (from, count, depth)
2344 Lisp_Object from, count, depth;
2346 CHECK_NUMBER (from, 0);
2347 CHECK_NUMBER (count, 1);
2348 CHECK_NUMBER (depth, 2);
2350 return scan_lists (XINT (from), XINT (count), XINT (depth), 0);
2353 DEFUN ("scan-sexps", Fscan_sexps, Sscan_sexps, 2, 2, 0,
2354 "Scan from character number FROM by COUNT balanced expressions.\n\
2355 If COUNT is negative, scan backwards.\n\
2356 Returns the character number of the position thus found.\n\
2358 Comments are ignored if `parse-sexp-ignore-comments' is non-nil.\n\
2360 If the beginning or end of (the accessible part of) the buffer is reached\n\
2361 in the middle of a parenthetical grouping, an error is signaled.\n\
2362 If the beginning or end is reached between groupings\n\
2363 but before count is used up, nil is returned.")
2364 (from, count)
2365 Lisp_Object from, count;
2367 CHECK_NUMBER (from, 0);
2368 CHECK_NUMBER (count, 1);
2370 return scan_lists (XINT (from), XINT (count), 0, 1);
2373 DEFUN ("backward-prefix-chars", Fbackward_prefix_chars, Sbackward_prefix_chars,
2374 0, 0, 0,
2375 "Move point backward over any number of chars with prefix syntax.\n\
2376 This includes chars with \"quote\" or \"prefix\" syntax (' or p).")
2379 int beg = BEGV;
2380 int opoint = PT;
2381 int opoint_byte = PT_BYTE;
2382 int pos = PT;
2383 int pos_byte = PT_BYTE;
2384 int c;
2386 if (pos <= beg)
2388 SET_PT_BOTH (opoint, opoint_byte);
2390 return Qnil;
2393 SETUP_SYNTAX_TABLE (pos, -1);
2395 DEC_BOTH (pos, pos_byte);
2397 while (!char_quoted (pos, pos_byte)
2398 /* Previous statement updates syntax table. */
2399 && ((c = FETCH_CHAR (pos_byte), SYNTAX (c) == Squote)
2400 || SYNTAX_PREFIX (c)))
2402 opoint = pos;
2403 opoint_byte = pos_byte;
2405 if (pos + 1 > beg)
2406 DEC_BOTH (pos, pos_byte);
2409 SET_PT_BOTH (opoint, opoint_byte);
2411 return Qnil;
2414 /* Parse forward from FROM / FROM_BYTE to END,
2415 assuming that FROM has state OLDSTATE (nil means FROM is start of function),
2416 and return a description of the state of the parse at END.
2417 If STOPBEFORE is nonzero, stop at the start of an atom.
2418 If COMMENTSTOP is 1, stop at the start of a comment.
2419 If COMMENTSTOP is -1, stop at the start or end of a comment,
2420 after the beginning of a string, or after the end of a string. */
2422 static void
2423 scan_sexps_forward (stateptr, from, from_byte, end, targetdepth,
2424 stopbefore, oldstate, commentstop)
2425 struct lisp_parse_state *stateptr;
2426 register int from;
2427 int end, targetdepth, stopbefore;
2428 Lisp_Object oldstate;
2429 int commentstop;
2431 struct lisp_parse_state state;
2433 register enum syntaxcode code;
2434 int c1;
2435 int comnested;
2436 struct level { int last, prev; };
2437 struct level levelstart[100];
2438 register struct level *curlevel = levelstart;
2439 struct level *endlevel = levelstart + 100;
2440 register int depth; /* Paren depth of current scanning location.
2441 level - levelstart equals this except
2442 when the depth becomes negative. */
2443 int mindepth; /* Lowest DEPTH value seen. */
2444 int start_quoted = 0; /* Nonzero means starting after a char quote */
2445 Lisp_Object tem;
2446 int prev_from; /* Keep one character before FROM. */
2447 int prev_from_byte;
2448 int prev_from_syntax;
2449 int boundary_stop = commentstop == -1;
2450 int nofence;
2451 int found;
2452 int out_bytepos, out_charpos;
2453 int temp;
2455 prev_from = from;
2456 prev_from_byte = from_byte;
2457 if (from != BEGV)
2458 DEC_BOTH (prev_from, prev_from_byte);
2460 /* Use this macro instead of `from++'. */
2461 #define INC_FROM \
2462 do { prev_from = from; \
2463 prev_from_byte = from_byte; \
2464 prev_from_syntax \
2465 = SYNTAX_WITH_FLAGS (FETCH_CHAR (prev_from_byte)); \
2466 INC_BOTH (from, from_byte); \
2467 UPDATE_SYNTAX_TABLE_FORWARD (from); \
2468 } while (0)
2470 immediate_quit = 1;
2471 QUIT;
2473 if (NILP (oldstate))
2475 depth = 0;
2476 state.instring = -1;
2477 state.incomment = 0;
2478 state.comstyle = 0; /* comment style a by default. */
2479 state.comstr_start = -1; /* no comment/string seen. */
2481 else
2483 tem = Fcar (oldstate);
2484 if (!NILP (tem))
2485 depth = XINT (tem);
2486 else
2487 depth = 0;
2489 oldstate = Fcdr (oldstate);
2490 oldstate = Fcdr (oldstate);
2491 oldstate = Fcdr (oldstate);
2492 tem = Fcar (oldstate);
2493 /* Check whether we are inside string_fence-style string: */
2494 state.instring = (!NILP (tem)
2495 ? (INTEGERP (tem) ? XINT (tem) : ST_STRING_STYLE)
2496 : -1);
2498 oldstate = Fcdr (oldstate);
2499 tem = Fcar (oldstate);
2500 state.incomment = (!NILP (tem)
2501 ? (INTEGERP (tem) ? XINT (tem) : -1)
2502 : 0);
2504 oldstate = Fcdr (oldstate);
2505 tem = Fcar (oldstate);
2506 start_quoted = !NILP (tem);
2508 /* if the eighth element of the list is nil, we are in comment
2509 style a. If it is non-nil, we are in comment style b */
2510 oldstate = Fcdr (oldstate);
2511 oldstate = Fcdr (oldstate);
2512 tem = Fcar (oldstate);
2513 state.comstyle = NILP (tem) ? 0 : (EQ (tem, Qsyntax_table)
2514 ? ST_COMMENT_STYLE : 1);
2516 oldstate = Fcdr (oldstate);
2517 tem = Fcar (oldstate);
2518 state.comstr_start = NILP (tem) ? -1 : XINT (tem) ;
2519 oldstate = Fcdr (oldstate);
2520 tem = Fcar (oldstate);
2521 while (!NILP (tem)) /* >= second enclosing sexps. */
2523 /* curlevel++->last ran into compiler bug on Apollo */
2524 curlevel->last = XINT (Fcar (tem));
2525 if (++curlevel == endlevel)
2526 error ("Nesting too deep for parser");
2527 curlevel->prev = -1;
2528 curlevel->last = -1;
2529 tem = Fcdr (tem);
2532 state.quoted = 0;
2533 mindepth = depth;
2535 curlevel->prev = -1;
2536 curlevel->last = -1;
2538 SETUP_SYNTAX_TABLE (prev_from, 1);
2539 prev_from_syntax = SYNTAX_WITH_FLAGS (FETCH_CHAR (prev_from_byte));
2540 UPDATE_SYNTAX_TABLE_FORWARD (from);
2542 /* Enter the loop at a place appropriate for initial state. */
2544 if (state.incomment)
2545 goto startincomment;
2546 if (state.instring >= 0)
2548 nofence = state.instring != ST_STRING_STYLE;
2549 if (start_quoted)
2550 goto startquotedinstring;
2551 goto startinstring;
2553 else if (start_quoted)
2554 goto startquoted;
2556 #if 0 /* This seems to be redundant with the identical code above. */
2557 SETUP_SYNTAX_TABLE (prev_from, 1);
2558 prev_from_syntax = SYNTAX_WITH_FLAGS (FETCH_CHAR (prev_from_byte));
2559 UPDATE_SYNTAX_TABLE_FORWARD (from);
2560 #endif
2562 while (from < end)
2564 INC_FROM;
2565 code = prev_from_syntax & 0xff;
2567 if (code == Scomment)
2569 state.incomment = (SYNTAX_FLAGS_COMMENT_NESTED (prev_from_syntax) ?
2570 1 : -1);
2571 state.comstr_start = prev_from;
2573 else if (code == Scomment_fence)
2575 /* Record the comment style we have entered so that only
2576 the comment-end sequence of the same style actually
2577 terminates the comment section. */
2578 state.comstyle = ST_COMMENT_STYLE;
2579 state.incomment = -1;
2580 state.comstr_start = prev_from;
2581 code = Scomment;
2583 else if (from < end)
2584 if (SYNTAX_FLAGS_COMSTART_FIRST (prev_from_syntax))
2585 if (c1 = FETCH_CHAR (from_byte),
2586 SYNTAX_COMSTART_SECOND (c1))
2587 /* Duplicate code to avoid a complex if-expression
2588 which causes trouble for the SGI compiler. */
2590 /* Record the comment style we have entered so that only
2591 the comment-end sequence of the same style actually
2592 terminates the comment section. */
2593 state.comstyle = SYNTAX_COMMENT_STYLE (FETCH_CHAR (from_byte));
2594 comnested = SYNTAX_FLAGS_COMMENT_NESTED (prev_from_syntax);
2595 comnested = comnested || SYNTAX_COMMENT_NESTED (c1);
2596 state.incomment = comnested ? 1 : -1;
2597 state.comstr_start = prev_from;
2598 INC_FROM;
2599 code = Scomment;
2602 if (SYNTAX_FLAGS_PREFIX (prev_from_syntax))
2603 continue;
2604 switch (SWITCH_ENUM_CAST (code))
2606 case Sescape:
2607 case Scharquote:
2608 if (stopbefore) goto stop; /* this arg means stop at sexp start */
2609 curlevel->last = prev_from;
2610 startquoted:
2611 if (from == end) goto endquoted;
2612 INC_FROM;
2613 goto symstarted;
2614 /* treat following character as a word constituent */
2615 case Sword:
2616 case Ssymbol:
2617 if (stopbefore) goto stop; /* this arg means stop at sexp start */
2618 curlevel->last = prev_from;
2619 symstarted:
2620 while (from < end)
2622 /* Some compilers can't handle this inside the switch. */
2623 temp = SYNTAX (FETCH_CHAR (from_byte));
2624 switch (temp)
2626 case Scharquote:
2627 case Sescape:
2628 INC_FROM;
2629 if (from == end) goto endquoted;
2630 break;
2631 case Sword:
2632 case Ssymbol:
2633 case Squote:
2634 break;
2635 default:
2636 goto symdone;
2638 INC_FROM;
2640 symdone:
2641 curlevel->prev = curlevel->last;
2642 break;
2644 startincomment:
2645 if (commentstop == 1)
2646 goto done;
2647 goto commentloop;
2649 case Scomment:
2650 if (! state.incomment)
2651 abort ();
2652 if (commentstop || boundary_stop) goto done;
2653 commentloop:
2654 /* The (from == BEGV) test is to enter the loop in the middle so
2655 that we find a 2-char comment ender even if we start in the
2656 middle of it. */
2657 found = forw_comment (from, from_byte, end,
2658 state.incomment, state.comstyle,
2659 (from == BEGV) ? 0 : prev_from_syntax,
2660 &out_charpos, &out_bytepos, &state.incomment);
2661 from = out_charpos; from_byte = out_bytepos;
2662 /* Beware! prev_from and friends are invalid now.
2663 Luckily, the `done' doesn't use them and the INC_FROM
2664 sets them to a sane value without looking at them. */
2665 if (!found) goto done;
2666 INC_FROM;
2667 state.incomment = 0;
2668 state.comstyle = 0; /* reset the comment style */
2669 if (boundary_stop) goto done;
2670 break;
2672 case Sopen:
2673 if (stopbefore) goto stop; /* this arg means stop at sexp start */
2674 depth++;
2675 /* curlevel++->last ran into compiler bug on Apollo */
2676 curlevel->last = prev_from;
2677 if (++curlevel == endlevel)
2678 error ("Nesting too deep for parser");
2679 curlevel->prev = -1;
2680 curlevel->last = -1;
2681 if (targetdepth == depth) goto done;
2682 break;
2684 case Sclose:
2685 depth--;
2686 if (depth < mindepth)
2687 mindepth = depth;
2688 if (curlevel != levelstart)
2689 curlevel--;
2690 curlevel->prev = curlevel->last;
2691 if (targetdepth == depth) goto done;
2692 break;
2694 case Sstring:
2695 case Sstring_fence:
2696 state.comstr_start = from - 1;
2697 if (stopbefore) goto stop; /* this arg means stop at sexp start */
2698 curlevel->last = prev_from;
2699 state.instring = (code == Sstring
2700 ? (FETCH_CHAR (prev_from_byte))
2701 : ST_STRING_STYLE);
2702 if (boundary_stop) goto done;
2703 startinstring:
2705 nofence = state.instring != ST_STRING_STYLE;
2707 while (1)
2709 int c;
2711 if (from >= end) goto done;
2712 c = FETCH_CHAR (from_byte);
2713 /* Some compilers can't handle this inside the switch. */
2714 temp = SYNTAX (c);
2716 /* Check TEMP here so that if the char has
2717 a syntax-table property which says it is NOT
2718 a string character, it does not end the string. */
2719 if (nofence && c == state.instring && temp == Sstring)
2720 break;
2722 switch (temp)
2724 case Sstring_fence:
2725 if (!nofence) goto string_end;
2726 break;
2727 case Scharquote:
2728 case Sescape:
2729 INC_FROM;
2730 startquotedinstring:
2731 if (from >= end) goto endquoted;
2733 INC_FROM;
2736 string_end:
2737 state.instring = -1;
2738 curlevel->prev = curlevel->last;
2739 INC_FROM;
2740 if (boundary_stop) goto done;
2741 break;
2743 case Smath:
2744 break;
2747 goto done;
2749 stop: /* Here if stopping before start of sexp. */
2750 from = prev_from; /* We have just fetched the char that starts it; */
2751 goto done; /* but return the position before it. */
2753 endquoted:
2754 state.quoted = 1;
2755 done:
2756 state.depth = depth;
2757 state.mindepth = mindepth;
2758 state.thislevelstart = curlevel->prev;
2759 state.prevlevelstart
2760 = (curlevel == levelstart) ? -1 : (curlevel - 1)->last;
2761 state.location = from;
2762 state.levelstarts = Qnil;
2763 while (--curlevel >= levelstart)
2764 state.levelstarts = Fcons (make_number (curlevel->last),
2765 state.levelstarts);
2766 immediate_quit = 0;
2768 *stateptr = state;
2771 /* This comment supplies the doc string for parse-partial-sexp,
2772 for make-docfile to see. We cannot put this in the real DEFUN
2773 due to limits in the Unix cpp.
2775 DEFUN ("parse-partial-sexp", Ffoo, Sfoo, 2, 6, 0,
2776 "Parse Lisp syntax starting at FROM until TO; return status of parse at TO.\n\
2777 Parsing stops at TO or when certain criteria are met;\n\
2778 point is set to where parsing stops.\n\
2779 If fifth arg STATE is omitted or nil,\n\
2780 parsing assumes that FROM is the beginning of a function.\n\
2781 Value is a list of ten elements describing final state of parsing:\n\
2782 0. depth in parens.\n\
2783 1. character address of start of innermost containing list; nil if none.\n\
2784 2. character address of start of last complete sexp terminated.\n\
2785 3. non-nil if inside a string.\n\
2786 (it is the character that will terminate the string,\n\
2787 or t if the string should be terminated by a generic string delimiter.)\n\
2788 4. nil if outside a comment, t if inside a non-nestable comment, \n\
2789 else an integer (the current comment nesting).\n\
2790 5. t if following a quote character.\n\
2791 6. the minimum paren-depth encountered during this scan.\n\
2792 7. t if in a comment of style b; `syntax-table' if the comment\n\
2793 should be terminated by a generic comment delimiter.\n\
2794 8. character address of start of comment or string; nil if not in one.\n\
2795 9. Intermediate data for continuation of parsing (subject to change).\n\
2796 If third arg TARGETDEPTH is non-nil, parsing stops if the depth\n\
2797 in parentheses becomes equal to TARGETDEPTH.\n\
2798 Fourth arg STOPBEFORE non-nil means stop when come to\n\
2799 any character that starts a sexp.\n\
2800 Fifth arg STATE is a nine-element list like what this function returns.\n\
2801 It is used to initialize the state of the parse. Elements number 1, 2, 6\n\
2802 and 8 are ignored; you can leave off element 8 (the last) entirely.\n\
2803 Sixth arg COMMENTSTOP non-nil means stop at the start of a comment.\n\
2804 If it is `syntax-table', stop after the start of a comment or a string,\n\
2805 or after end of a comment or a string.")
2806 (from, to, targetdepth, stopbefore, state, commentstop)
2809 DEFUN ("parse-partial-sexp", Fparse_partial_sexp, Sparse_partial_sexp, 2, 6, 0,
2810 0 /* See immediately above */)
2811 (from, to, targetdepth, stopbefore, oldstate, commentstop)
2812 Lisp_Object from, to, targetdepth, stopbefore, oldstate, commentstop;
2814 struct lisp_parse_state state;
2815 int target;
2817 if (!NILP (targetdepth))
2819 CHECK_NUMBER (targetdepth, 3);
2820 target = XINT (targetdepth);
2822 else
2823 target = -100000; /* We won't reach this depth */
2825 validate_region (&from, &to);
2826 scan_sexps_forward (&state, XINT (from), CHAR_TO_BYTE (XINT (from)),
2827 XINT (to),
2828 target, !NILP (stopbefore), oldstate,
2829 (NILP (commentstop)
2830 ? 0 : (EQ (commentstop, Qsyntax_table) ? -1 : 1)));
2832 SET_PT (state.location);
2834 return Fcons (make_number (state.depth),
2835 Fcons (state.prevlevelstart < 0 ? Qnil : make_number (state.prevlevelstart),
2836 Fcons (state.thislevelstart < 0 ? Qnil : make_number (state.thislevelstart),
2837 Fcons (state.instring >= 0
2838 ? (state.instring == ST_STRING_STYLE
2839 ? Qt : make_number (state.instring)) : Qnil,
2840 Fcons (state.incomment < 0 ? Qt :
2841 (state.incomment == 0 ? Qnil :
2842 make_number (state.incomment)),
2843 Fcons (state.quoted ? Qt : Qnil,
2844 Fcons (make_number (state.mindepth),
2845 Fcons ((state.comstyle
2846 ? (state.comstyle == ST_COMMENT_STYLE
2847 ? Qsyntax_table : Qt) :
2848 Qnil),
2849 Fcons (((state.incomment
2850 || (state.instring >= 0))
2851 ? make_number (state.comstr_start)
2852 : Qnil),
2853 Fcons (state.levelstarts, Qnil))))))))));
2856 void
2857 init_syntax_once ()
2859 register int i, c;
2860 Lisp_Object temp;
2862 /* This has to be done here, before we call Fmake_char_table. */
2863 Qsyntax_table = intern ("syntax-table");
2864 staticpro (&Qsyntax_table);
2866 /* Intern this now in case it isn't already done.
2867 Setting this variable twice is harmless.
2868 But don't staticpro it here--that is done in alloc.c. */
2869 Qchar_table_extra_slots = intern ("char-table-extra-slots");
2871 /* Create objects which can be shared among syntax tables. */
2872 Vsyntax_code_object = Fmake_vector (make_number (13), Qnil);
2873 for (i = 0; i < XVECTOR (Vsyntax_code_object)->size; i++)
2874 XVECTOR (Vsyntax_code_object)->contents[i]
2875 = Fcons (make_number (i), Qnil);
2877 /* Now we are ready to set up this property, so we can
2878 create syntax tables. */
2879 Fput (Qsyntax_table, Qchar_table_extra_slots, make_number (0));
2881 temp = XVECTOR (Vsyntax_code_object)->contents[(int) Swhitespace];
2883 Vstandard_syntax_table = Fmake_char_table (Qsyntax_table, temp);
2885 temp = XVECTOR (Vsyntax_code_object)->contents[(int) Sword];
2886 for (i = 'a'; i <= 'z'; i++)
2887 SET_RAW_SYNTAX_ENTRY (Vstandard_syntax_table, i, temp);
2888 for (i = 'A'; i <= 'Z'; i++)
2889 SET_RAW_SYNTAX_ENTRY (Vstandard_syntax_table, i, temp);
2890 for (i = '0'; i <= '9'; i++)
2891 SET_RAW_SYNTAX_ENTRY (Vstandard_syntax_table, i, temp);
2893 SET_RAW_SYNTAX_ENTRY (Vstandard_syntax_table, '$', temp);
2894 SET_RAW_SYNTAX_ENTRY (Vstandard_syntax_table, '%', temp);
2896 SET_RAW_SYNTAX_ENTRY (Vstandard_syntax_table, '(',
2897 Fcons (make_number (Sopen), make_number (')')));
2898 SET_RAW_SYNTAX_ENTRY (Vstandard_syntax_table, ')',
2899 Fcons (make_number (Sclose), make_number ('(')));
2900 SET_RAW_SYNTAX_ENTRY (Vstandard_syntax_table, '[',
2901 Fcons (make_number (Sopen), make_number (']')));
2902 SET_RAW_SYNTAX_ENTRY (Vstandard_syntax_table, ']',
2903 Fcons (make_number (Sclose), make_number ('[')));
2904 SET_RAW_SYNTAX_ENTRY (Vstandard_syntax_table, '{',
2905 Fcons (make_number (Sopen), make_number ('}')));
2906 SET_RAW_SYNTAX_ENTRY (Vstandard_syntax_table, '}',
2907 Fcons (make_number (Sclose), make_number ('{')));
2908 SET_RAW_SYNTAX_ENTRY (Vstandard_syntax_table, '"',
2909 Fcons (make_number ((int) Sstring), Qnil));
2910 SET_RAW_SYNTAX_ENTRY (Vstandard_syntax_table, '\\',
2911 Fcons (make_number ((int) Sescape), Qnil));
2913 temp = XVECTOR (Vsyntax_code_object)->contents[(int) Ssymbol];
2914 for (i = 0; i < 10; i++)
2916 c = "_-+*/&|<>="[i];
2917 SET_RAW_SYNTAX_ENTRY (Vstandard_syntax_table, c, temp);
2920 temp = XVECTOR (Vsyntax_code_object)->contents[(int) Spunct];
2921 for (i = 0; i < 12; i++)
2923 c = ".,;:?!#@~^'`"[i];
2924 SET_RAW_SYNTAX_ENTRY (Vstandard_syntax_table, c, temp);
2927 /* All multibyte characters have syntax `word' by default. */
2928 temp = XVECTOR (Vsyntax_code_object)->contents[(int) Sword];
2929 for (i = CHAR_TABLE_SINGLE_BYTE_SLOTS; i < CHAR_TABLE_ORDINARY_SLOTS; i++)
2930 XCHAR_TABLE (Vstandard_syntax_table)->contents[i] = temp;
2933 void
2934 syms_of_syntax ()
2936 Qsyntax_table_p = intern ("syntax-table-p");
2937 staticpro (&Qsyntax_table_p);
2939 staticpro (&Vsyntax_code_object);
2941 Qscan_error = intern ("scan-error");
2942 staticpro (&Qscan_error);
2943 Fput (Qscan_error, Qerror_conditions,
2944 Fcons (Qscan_error, Fcons (Qerror, Qnil)));
2945 Fput (Qscan_error, Qerror_message,
2946 build_string ("Scan error"));
2948 DEFVAR_BOOL ("parse-sexp-ignore-comments", &parse_sexp_ignore_comments,
2949 "Non-nil means `forward-sexp', etc., should treat comments as whitespace.");
2951 DEFVAR_BOOL ("parse-sexp-lookup-properties", &parse_sexp_lookup_properties,
2952 "Non-nil means `forward-sexp', etc., grant `syntax-table' property.\n\
2953 The value of this property should be either a syntax table, or a cons\n\
2954 of the form (SYNTAXCODE . MATCHCHAR), SYNTAXCODE being the numeric\n\
2955 syntax code, MATCHCHAR being nil or the character to match (which is\n\
2956 relevant only for open/close type.");
2958 words_include_escapes = 0;
2959 DEFVAR_BOOL ("words-include-escapes", &words_include_escapes,
2960 "Non-nil means `forward-word', etc., should treat escape chars part of words.");
2962 DEFVAR_BOOL ("multibyte-syntax-as-symbol", &multibyte_syntax_as_symbol,
2963 "Non-nil means `scan-sexps' treats all multibyte characters as symbol.");
2964 multibyte_syntax_as_symbol = 0;
2966 defsubr (&Ssyntax_table_p);
2967 defsubr (&Ssyntax_table);
2968 defsubr (&Sstandard_syntax_table);
2969 defsubr (&Scopy_syntax_table);
2970 defsubr (&Sset_syntax_table);
2971 defsubr (&Schar_syntax);
2972 defsubr (&Smatching_paren);
2973 defsubr (&Smodify_syntax_entry);
2974 defsubr (&Sdescribe_syntax);
2976 defsubr (&Sforward_word);
2978 defsubr (&Sskip_chars_forward);
2979 defsubr (&Sskip_chars_backward);
2980 defsubr (&Sskip_syntax_forward);
2981 defsubr (&Sskip_syntax_backward);
2983 defsubr (&Sforward_comment);
2984 defsubr (&Sscan_lists);
2985 defsubr (&Sscan_sexps);
2986 defsubr (&Sbackward_prefix_chars);
2987 defsubr (&Sparse_partial_sexp);