1 /* GNU Emacs routines to deal with syntax tables; also word and list parsing.
2 Copyright (C) 1985, 1987, 1993, 1994, 1995 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)
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. */
29 Lisp_Object Qsyntax_table_p
, Qsyntax_table
;
31 static void scan_sexps_forward ();
32 static int char_quoted ();
34 int words_include_escapes
;
36 /* Used as a temporary in SYNTAX_ENTRY and other macros in syntax.h,
37 if not compiled with GCC. No need to mark it, since it is used
38 only very temporarily. */
39 Lisp_Object syntax_temp
;
41 /* This is the internal form of the parse state used in parse-partial-sexp. */
43 struct lisp_parse_state
45 int depth
; /* Depth at end of parsing */
46 int instring
; /* -1 if not within string, else desired terminator. */
47 int incomment
; /* Nonzero if within a comment at end of parsing */
48 int comstyle
; /* comment style a=0, or b=1 */
49 int quoted
; /* Nonzero if just after an escape char at end of parsing */
50 int thislevelstart
; /* Char number of most recent start-of-expression at current level */
51 int prevlevelstart
; /* Char number of start of containing expression */
52 int location
; /* Char number at which parsing stopped. */
53 int mindepth
; /* Minimum depth seen while scanning. */
54 int comstart
; /* Position just after last comment starter. */
57 /* These variables are a cache for finding the start of a defun.
58 find_start_pos is the place for which the defun start was found.
59 find_start_value is the defun start position found for it.
60 find_start_buffer is the buffer it was found in.
61 find_start_begv is the BEGV value when it was found.
62 find_start_modiff is the value of MODIFF when it was found. */
64 static int find_start_pos
;
65 static int find_start_value
;
66 static struct buffer
*find_start_buffer
;
67 static int find_start_begv
;
68 static int find_start_modiff
;
70 /* Find a defun-start that is the last one before POS (or nearly the last).
71 We record what we find, so that another call in the same area
72 can return the same value right away. */
75 find_defun_start (pos
)
81 /* Use previous finding, if it's valid and applies to this inquiry. */
82 if (current_buffer
== find_start_buffer
83 /* Reuse the defun-start even if POS is a little farther on.
84 POS might be in the next defun, but that's ok.
85 Our value may not be the best possible, but will still be usable. */
86 && pos
<= find_start_pos
+ 1000
87 && pos
>= find_start_value
88 && BEGV
== find_start_begv
89 && MODIFF
== find_start_modiff
)
90 return find_start_value
;
92 /* Back up to start of line. */
93 tem
= scan_buffer ('\n', pos
, BEGV
, -1, &shortage
, 1);
97 /* Open-paren at start of line means we found our defun-start. */
98 if (SYNTAX (FETCH_CHAR (tem
)) == Sopen
)
100 /* Move to beg of previous line. */
101 tem
= scan_buffer ('\n', tem
, BEGV
, -2, &shortage
, 1);
104 /* Record what we found, for the next try. */
105 find_start_value
= tem
;
106 find_start_buffer
= current_buffer
;
107 find_start_modiff
= MODIFF
;
108 find_start_begv
= BEGV
;
109 find_start_pos
= pos
;
111 return find_start_value
;
114 DEFUN ("syntax-table-p", Fsyntax_table_p
, Ssyntax_table_p
, 1, 1, 0,
115 "Return t if OBJECT is a syntax table.\n\
116 Currently, any char-table counts as a syntax table.")
120 if (CHAR_TABLE_P (object
)
121 && XCHAR_TABLE (object
)->purpose
== Qsyntax_table
)
127 check_syntax_table (obj
)
130 if (!(CHAR_TABLE_P (obj
)
131 && XCHAR_TABLE (obj
)->purpose
== Qsyntax_table
))
132 wrong_type_argument (Qsyntax_table_p
, obj
);
135 DEFUN ("syntax-table", Fsyntax_table
, Ssyntax_table
, 0, 0, 0,
136 "Return the current syntax table.\n\
137 This is the one specified by the current buffer.")
140 return current_buffer
->syntax_table
;
143 DEFUN ("standard-syntax-table", Fstandard_syntax_table
,
144 Sstandard_syntax_table
, 0, 0, 0,
145 "Return the standard syntax table.\n\
146 This is the one used for new buffers.")
149 return Vstandard_syntax_table
;
152 DEFUN ("copy-syntax-table", Fcopy_syntax_table
, Scopy_syntax_table
, 0, 1, 0,
153 "Construct a new syntax table and return it.\n\
154 It is a copy of the TABLE, which defaults to the standard syntax table.")
161 check_syntax_table (table
);
163 table
= Vstandard_syntax_table
;
165 copy
= Fcopy_sequence (table
);
167 /* Only the standard syntax table should have a default element.
168 Other syntax tables should inherit from parents instead. */
169 XCHAR_TABLE (copy
)->defalt
= Qnil
;
171 /* Copied syntax tables should all have parents.
172 If we copied one with no parent, such as the standard syntax table,
173 use the standard syntax table as the copy's parent. */
174 if (NILP (XCHAR_TABLE (copy
)->parent
))
175 Fset_char_table_parent (copy
, Vstandard_syntax_table
);
179 DEFUN ("set-syntax-table", Fset_syntax_table
, Sset_syntax_table
, 1, 1, 0,
180 "Select a new syntax table for the current buffer.\n\
181 One argument, a syntax table.")
185 check_syntax_table (table
);
186 current_buffer
->syntax_table
= table
;
187 /* Indicate that this buffer now has a specified syntax table. */
188 current_buffer
->local_var_flags
189 |= XFASTINT (buffer_local_flags
.syntax_table
);
193 /* Convert a letter which signifies a syntax code
194 into the code it signifies.
195 This is used by modify-syntax-entry, and other things. */
197 unsigned char syntax_spec_code
[0400] =
198 { 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377,
199 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377,
200 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377,
201 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377,
202 (char) Swhitespace
, 0377, (char) Sstring
, 0377,
203 (char) Smath
, 0377, 0377, (char) Squote
,
204 (char) Sopen
, (char) Sclose
, 0377, 0377,
205 0377, (char) Swhitespace
, (char) Spunct
, (char) Scharquote
,
206 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377,
207 0377, 0377, 0377, 0377,
208 (char) Scomment
, 0377, (char) Sendcomment
, 0377,
209 (char) Sinherit
, 0377, 0377, 0377, 0377, 0377, 0377, 0377, /* @, A ... */
210 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377,
211 0377, 0377, 0377, 0377, 0377, 0377, 0377, (char) Sword
,
212 0377, 0377, 0377, 0377, (char) Sescape
, 0377, 0377, (char) Ssymbol
,
213 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, /* `, a, ... */
214 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377,
215 0377, 0377, 0377, 0377, 0377, 0377, 0377, (char) Sword
,
216 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377
219 /* Indexed by syntax code, give the letter that describes it. */
221 char syntax_code_spec
[14] =
223 ' ', '.', 'w', '_', '(', ')', '\'', '\"', '$', '\\', '/', '<', '>', '@'
226 /* Look up the value for CHARACTER in syntax table TABLE's parent
227 and its parents. SYNTAX_ENTRY calls this, when TABLE itself has nil
228 for CHARACTER. It's actually used only when not compiled with GCC. */
231 syntax_parent_lookup (table
, character
)
239 table
= XCHAR_TABLE (table
)->parent
;
243 value
= XCHAR_TABLE (table
)->contents
[character
];
249 DEFUN ("char-syntax", Fchar_syntax
, Schar_syntax
, 1, 1, 0,
250 "Return the syntax code of CHARACTER, described by a character.\n\
251 For example, if CHARACTER is a word constituent,\n\
252 the character `w' is returned.\n\
253 The characters that correspond to various syntax codes\n\
254 are listed in the documentation of `modify-syntax-entry'.")
256 Lisp_Object character
;
259 CHECK_NUMBER (character
, 0);
260 char_int
= XINT (character
);
261 return make_number (syntax_code_spec
[(int) SYNTAX (char_int
)]);
264 DEFUN ("matching-paren", Fmatching_paren
, Smatching_paren
, 1, 1, 0,
265 "Return the matching parenthesis of CHARACTER, or nil if none.")
267 Lisp_Object character
;
270 CHECK_NUMBER (character
, 0);
271 char_int
= XINT (character
);
272 code
= SYNTAX (char_int
);
273 if (code
== Sopen
|| code
== Sclose
)
274 return make_number (SYNTAX_MATCH (char_int
));
278 /* This comment supplies the doc string for modify-syntax-entry,
279 for make-docfile to see. We cannot put this in the real DEFUN
280 due to limits in the Unix cpp.
282 DEFUN ("modify-syntax-entry", foo, bar, 2, 3, 0,
283 "Set syntax for character CHAR according to string S.\n\
284 The syntax is changed only for table TABLE, which defaults to\n\
285 the current buffer's syntax table.\n\
286 The first character of S should be one of the following:\n\
287 Space or - whitespace syntax. w word constituent.\n\
288 _ symbol constituent. . punctuation.\n\
289 ( open-parenthesis. ) close-parenthesis.\n\
290 \" string quote. \\ escape.\n\
291 $ paired delimiter. ' expression quote or prefix operator.\n\
292 < comment starter. > comment ender.\n\
293 / character-quote. @ inherit from `standard-syntax-table'.\n\
295 Only single-character comment start and end sequences are represented thus.\n\
296 Two-character sequences are represented as described below.\n\
297 The second character of S is the matching parenthesis,\n\
298 used only if the first character is `(' or `)'.\n\
299 Any additional characters are flags.\n\
300 Defined flags are the characters 1, 2, 3, 4, b, and p.\n\
301 1 means CHAR is the start of a two-char comment start sequence.\n\
302 2 means CHAR is the second character of such a sequence.\n\
303 3 means CHAR is the start of a two-char comment end sequence.\n\
304 4 means CHAR is the second character of such a sequence.\n\
306 There can be up to two orthogonal comment sequences. This is to support\n\
307 language modes such as C++. By default, all comment sequences are of style\n\
308 a, but you can set the comment sequence style to b (on the second character\n\
309 of a comment-start, or the first character of a comment-end sequence) using\n\
311 b means CHAR is part of comment sequence b.\n\
313 p means CHAR is a prefix character for `backward-prefix-chars';\n\
314 such characters are treated as whitespace when they occur\n\
315 between expressions.")
319 DEFUN ("modify-syntax-entry", Fmodify_syntax_entry
, Smodify_syntax_entry
, 2, 3,
320 /* I really don't know why this is interactive
321 help-form should at least be made useful whilst reading the second arg
323 "cSet syntax for character: \nsSet syntax for %s to: ",
324 0 /* See immediately above */)
325 (c
, newentry
, syntax_table
)
326 Lisp_Object c
, newentry
, syntax_table
;
328 register unsigned char *p
;
329 register enum syntaxcode code
;
334 CHECK_STRING (newentry
, 1);
336 if (NILP (syntax_table
))
337 syntax_table
= current_buffer
->syntax_table
;
339 check_syntax_table (syntax_table
);
341 p
= XSTRING (newentry
)->data
;
342 code
= (enum syntaxcode
) syntax_spec_code
[*p
++];
343 if (((int) code
& 0377) == 0377)
344 error ("invalid syntax description letter: %c", c
);
346 if (code
== Sinherit
)
348 SET_RAW_SYNTAX_ENTRY (syntax_table
, c
, Qnil
);
354 XSETINT (match
, *p
++);
355 if (XFASTINT (match
) == ' ')
390 SET_RAW_SYNTAX_ENTRY (syntax_table
, c
,
391 Fcons (make_number (val
), match
));
396 /* Dump syntax table to buffer in human-readable format */
399 describe_syntax (value
)
402 register enum syntaxcode code
;
403 char desc
, match
, start1
, start2
, end1
, end2
, prefix
, comstyle
;
405 Lisp_Object first
, match_lisp
;
407 Findent_to (make_number (16), make_number (1));
411 insert_string ("inherit");
417 insert_string ("invalid");
421 first
= XCONS (value
)->car
;
422 match_lisp
= XCONS (value
)->cdr
;
424 if (!INTEGERP (first
) || !(NILP (match_lisp
) || INTEGERP (match_lisp
)))
426 insert_string ("invalid");
430 code
= (enum syntaxcode
) (first
& 0377);
431 start1
= (XINT (first
) >> 16) & 1;
432 start2
= (XINT (first
) >> 17) & 1;
433 end1
= (XINT (first
) >> 18) & 1;
434 end2
= (XINT (first
) >> 19) & 1;
435 prefix
= (XINT (first
) >> 20) & 1;
436 comstyle
= (XINT (first
) >> 21) & 1;
438 if ((int) code
< 0 || (int) code
>= (int) Smax
)
440 insert_string ("invalid");
443 desc
= syntax_code_spec
[(int) code
];
445 str
[0] = desc
, str
[1] = 0;
448 str
[0] = !NILP (match_lisp
) ? XINT (match_lisp
) : ' ';
466 insert_string ("\twhich means: ");
468 switch (SWITCH_ENUM_CAST (code
))
471 insert_string ("whitespace"); break;
473 insert_string ("punctuation"); break;
475 insert_string ("word"); break;
477 insert_string ("symbol"); break;
479 insert_string ("open"); break;
481 insert_string ("close"); break;
483 insert_string ("quote"); break;
485 insert_string ("string"); break;
487 insert_string ("math"); break;
489 insert_string ("escape"); break;
491 insert_string ("charquote"); break;
493 insert_string ("comment"); break;
495 insert_string ("endcomment"); break;
497 insert_string ("invalid");
501 if (!NILP (match_lisp
))
503 insert_string (", matches ");
504 insert_char (XINT (match_lisp
));
508 insert_string (",\n\t is the first character of a comment-start sequence");
510 insert_string (",\n\t is the second character of a comment-start sequence");
513 insert_string (",\n\t is the first character of a comment-end sequence");
515 insert_string (",\n\t is the second character of a comment-end sequence");
517 insert_string (" (comment style b)");
520 insert_string (",\n\t is a prefix character for `backward-prefix-chars'");
522 insert_string ("\n");
526 describe_syntax_1 (vector
)
529 struct buffer
*old
= current_buffer
;
530 set_buffer_internal (XBUFFER (Vstandard_output
));
531 describe_vector (vector
, Qnil
, describe_syntax
, 0, Qnil
, Qnil
);
532 call0 (intern ("help-mode"));
533 set_buffer_internal (old
);
537 DEFUN ("describe-syntax", Fdescribe_syntax
, Sdescribe_syntax
, 0, 0, "",
538 "Describe the syntax specifications in the syntax table.\n\
539 The descriptions are inserted in a buffer, which is then displayed.")
542 internal_with_output_to_temp_buffer
543 ("*Help*", describe_syntax_1
, current_buffer
->syntax_table
);
548 /* Return the position across COUNT words from FROM.
549 If that many words cannot be found before the end of the buffer, return 0.
550 COUNT negative means scan backward and stop at word beginning. */
552 scan_words (from
, count
)
553 register int from
, count
;
555 register int beg
= BEGV
;
556 register int end
= ZV
;
572 charcode
= FETCH_CHAR (from
);
573 code
= SYNTAX (charcode
);
574 if (words_include_escapes
575 && (code
== Sescape
|| code
== Scharquote
))
583 if (from
== end
) break;
584 charcode
= FETCH_CHAR (from
);
585 code
= SYNTAX (charcode
);
586 if (!(words_include_escapes
587 && (code
== Sescape
|| code
== Scharquote
)))
603 charcode
= FETCH_CHAR (from
- 1);
604 code
= SYNTAX (charcode
);
605 if (words_include_escapes
606 && (code
== Sescape
|| code
== Scharquote
))
614 if (from
== beg
) break;
615 charcode
= FETCH_CHAR (from
- 1);
616 code
= SYNTAX (charcode
);
617 if (!(words_include_escapes
618 && (code
== Sescape
|| code
== Scharquote
)))
631 DEFUN ("forward-word", Fforward_word
, Sforward_word
, 1, 1, "p",
632 "Move point forward ARG words (backward if ARG is negative).\n\
633 Normally returns t.\n\
634 If an edge of the buffer is reached, point is left there\n\
635 and nil is returned.")
640 CHECK_NUMBER (count
, 0);
642 if (!(val
= scan_words (point
, XINT (count
))))
644 SET_PT (XINT (count
) > 0 ? ZV
: BEGV
);
651 DEFUN ("forward-comment", Fforward_comment
, Sforward_comment
, 1, 1, 0,
652 "Move forward across up to N comments. If N is negative, move backward.\n\
653 Stop scanning if we find something other than a comment or whitespace.\n\
654 Set point to where scanning stops.\n\
655 If N comments are found as expected, with nothing except whitespace\n\
656 between them, return t; otherwise return nil.")
663 register enum syntaxcode code
;
664 int comstyle
= 0; /* style of comment encountered */
668 CHECK_NUMBER (count
, 0);
669 count1
= XINT (count
);
687 c
= FETCH_CHAR (from
);
691 if (from
< stop
&& SYNTAX_COMSTART_FIRST (c
)
692 && (c1
= FETCH_CHAR (from
),
693 SYNTAX_COMSTART_SECOND (c1
)))
695 /* We have encountered a comment start sequence and we
696 are ignoring all text inside comments. We must record
697 the comment style this sequence begins so that later,
698 only a comment end of the same style actually ends
699 the comment section. */
701 comstyle
= SYNTAX_COMMENT_STYLE (c1
);
705 while (code
== Swhitespace
|| code
== Sendcomment
);
706 if (code
!= Scomment
)
712 /* We're at the start of a comment. */
721 c
= FETCH_CHAR (from
);
723 if (SYNTAX (c
) == Sendcomment
724 && SYNTAX_COMMENT_STYLE (c
) == comstyle
)
725 /* we have encountered a comment end of the same style
726 as the comment sequence which began this comment
729 if (from
< stop
&& SYNTAX_COMEND_FIRST (c
)
730 && (c1
= FETCH_CHAR (from
),
731 SYNTAX_COMEND_SECOND (c1
))
732 && SYNTAX_COMMENT_STYLE (c
) == comstyle
)
733 /* we have encountered a comment end of the same style
734 as the comment sequence which began this comment
738 /* We have skipped one comment. */
750 quoted
= char_quoted (from
);
753 c
= FETCH_CHAR (from
);
756 if (code
== Sendcomment
)
757 comstyle
= SYNTAX_COMMENT_STYLE (c
);
758 if (from
> stop
&& SYNTAX_COMEND_SECOND (c
)
759 && (c1
= FETCH_CHAR (from
- 1),
760 SYNTAX_COMEND_FIRST (c1
))
761 && !char_quoted (from
- 1))
763 /* We must record the comment style encountered so that
764 later, we can match only the proper comment begin
765 sequence of the same style. */
767 comstyle
= SYNTAX_COMMENT_STYLE (c1
);
771 if (code
== Sendcomment
&& !quoted
)
774 if (code
!= SYNTAX (c
))
775 /* For a two-char comment ender, we can assume
776 it does end a comment. So scan back in a simple way. */
778 if (from
!= stop
) from
--;
781 if ((c
= FETCH_CHAR (from
),
782 SYNTAX (c
) == Scomment
)
783 && SYNTAX_COMMENT_STYLE (c
) == comstyle
)
792 if (SYNTAX_COMSTART_SECOND (c
)
793 && (c1
= FETCH_CHAR (from
),
794 SYNTAX_COMSTART_FIRST (c1
))
795 && SYNTAX_COMMENT_STYLE (c
) == comstyle
796 && !char_quoted (from
))
803 /* Look back, counting the parity of string-quotes,
804 and recording the comment-starters seen.
805 When we reach a safe place, assume that's not in a string;
806 then step the main scan to the earliest comment-starter seen
807 an even number of string quotes away from the safe place.
809 OFROM[I] is position of the earliest comment-starter seen
810 which is I+2X quotes from the comment-end.
811 PARITY is current parity of quotes from the comment end. */
814 char my_stringend
= 0;
815 int string_lossage
= 0;
816 int comment_end
= from
;
817 int comstart_pos
= 0;
818 int comstart_parity
= 0;
819 int scanstart
= from
- 1;
821 /* At beginning of range to scan, we're outside of strings;
822 that determines quote parity to the comment-end. */
825 /* Move back and examine a character. */
828 c
= FETCH_CHAR (from
);
831 /* If this char is the second of a 2-char comment sequence,
832 back up and give the pair the appropriate syntax. */
833 if (from
> stop
&& SYNTAX_COMEND_SECOND (c
)
834 && SYNTAX_COMEND_FIRST (FETCH_CHAR (from
- 1)))
838 c
= FETCH_CHAR (from
);
841 /* If this char starts a 2-char comment start sequence,
842 treat it like a 1-char comment starter. */
843 if (from
< scanstart
&& SYNTAX_COMSTART_FIRST (c
)
844 && SYNTAX_COMSTART_SECOND (FETCH_CHAR (from
+ 1))
845 && comstyle
== SYNTAX_COMMENT_STYLE (FETCH_CHAR (from
+ 1)))
848 /* Ignore escaped characters. */
849 if (char_quoted (from
))
852 /* Track parity of quotes. */
856 if (my_stringend
== 0)
858 /* If we have two kinds of string delimiters.
859 There's no way to grok this scanning backwards. */
860 else if (my_stringend
!= c
)
864 /* Record comment-starters according to that
865 quote-parity to the comment-end. */
866 if (code
== Scomment
)
868 comstart_parity
= parity
;
872 /* If we find another earlier comment-ender,
873 any comment-starts earlier than that don't count
874 (because they go with the earlier comment-ender). */
875 if (code
== Sendcomment
876 && SYNTAX_COMMENT_STYLE (FETCH_CHAR (from
)) == comstyle
)
879 /* Assume a defun-start point is outside of strings. */
881 && (from
== stop
|| FETCH_CHAR (from
- 1) == '\n'))
885 if (comstart_pos
== 0)
887 /* If the earliest comment starter
888 is followed by uniform paired string quotes or none,
889 we know it can't be inside a string
890 since if it were then the comment ender would be inside one.
891 So it does start a comment. Skip back to it. */
892 else if (comstart_parity
== 0 && !string_lossage
)
896 /* We had two kinds of string delimiters mixed up
897 together. Decode this going forwards.
898 Scan fwd from the previous comment ender
899 to the one in question; this records where we
900 last passed a comment starter. */
901 struct lisp_parse_state state
;
902 scan_sexps_forward (&state
, find_defun_start (comment_end
),
903 comment_end
- 1, -10000, 0, Qnil
, 0);
905 from
= state
.comstart
;
907 /* We can't grok this as a comment; scan it normally. */
911 /* We have skipped one comment. */
914 else if ((code
!= Swhitespace
&& code
!= Scomment
) || quoted
)
930 int parse_sexp_ignore_comments
;
933 scan_lists (from
, count
, depth
, sexpflag
)
935 int count
, depth
, sexpflag
;
940 unsigned char stringterm
;
943 register enum syntaxcode code
;
944 int min_depth
= depth
; /* Err out if depth gets less than this. */
945 int comstyle
= 0; /* style of comment encountered */
947 if (depth
> 0) min_depth
= 0;
957 c
= FETCH_CHAR (from
);
960 if (from
< stop
&& SYNTAX_COMSTART_FIRST (c
)
961 && SYNTAX_COMSTART_SECOND (FETCH_CHAR (from
))
962 && parse_sexp_ignore_comments
)
964 /* we have encountered a comment start sequence and we
965 are ignoring all text inside comments. we must record
966 the comment style this sequence begins so that later,
967 only a comment end of the same style actually ends
968 the comment section */
970 comstyle
= SYNTAX_COMMENT_STYLE (FETCH_CHAR (from
));
974 if (SYNTAX_PREFIX (c
))
977 switch (SWITCH_ENUM_CAST (code
))
981 if (from
== stop
) goto lose
;
983 /* treat following character as a word constituent */
986 if (depth
|| !sexpflag
) break;
987 /* This word counts as a sexp; return at end of it. */
990 switch (SWITCH_ENUM_CAST (SYNTAX (FETCH_CHAR (from
))))
995 if (from
== stop
) goto lose
;
1009 if (!parse_sexp_ignore_comments
) break;
1018 c
= FETCH_CHAR (from
);
1019 if (SYNTAX (c
) == Sendcomment
1020 && SYNTAX_COMMENT_STYLE (c
) == comstyle
)
1021 /* we have encountered a comment end of the same style
1022 as the comment sequence which began this comment
1026 if (from
< stop
&& SYNTAX_COMEND_FIRST (c
)
1027 && SYNTAX_COMEND_SECOND (FETCH_CHAR (from
))
1028 && SYNTAX_COMMENT_STYLE (c
) == comstyle
)
1029 /* we have encountered a comment end of the same style
1030 as the comment sequence which began this comment
1039 if (from
!= stop
&& c
== FETCH_CHAR (from
))
1049 if (!++depth
) goto done
;
1054 if (!--depth
) goto done
;
1055 if (depth
< min_depth
)
1056 error ("Containing expression ends prematurely");
1060 stringterm
= FETCH_CHAR (from
- 1);
1063 if (from
>= stop
) goto lose
;
1064 if (FETCH_CHAR (from
) == stringterm
) break;
1065 switch (SWITCH_ENUM_CAST (SYNTAX (FETCH_CHAR (from
))))
1074 if (!depth
&& sexpflag
) goto done
;
1079 /* Reached end of buffer. Error if within object, return nil if between */
1080 if (depth
) goto lose
;
1085 /* End of object reached */
1096 if (quoted
= char_quoted (from
))
1098 c
= FETCH_CHAR (from
);
1101 if (code
== Sendcomment
)
1102 comstyle
= SYNTAX_COMMENT_STYLE (c
);
1103 if (from
> stop
&& SYNTAX_COMEND_SECOND (c
)
1104 && SYNTAX_COMEND_FIRST (FETCH_CHAR (from
- 1))
1105 && !char_quoted (from
- 1)
1106 && parse_sexp_ignore_comments
)
1108 /* we must record the comment style encountered so that
1109 later, we can match only the proper comment begin
1110 sequence of the same style */
1112 comstyle
= SYNTAX_COMMENT_STYLE (FETCH_CHAR (from
- 1));
1116 if (SYNTAX_PREFIX (c
))
1119 switch (SWITCH_ENUM_CAST (quoted
? Sword
: code
))
1123 if (depth
|| !sexpflag
) break;
1124 /* This word counts as a sexp; count object finished after passing it. */
1127 quoted
= char_quoted (from
- 1);
1130 if (! (quoted
|| SYNTAX (FETCH_CHAR (from
- 1)) == Sword
1131 || SYNTAX (FETCH_CHAR (from
- 1)) == Ssymbol
1132 || SYNTAX (FETCH_CHAR (from
- 1)) == Squote
))
1141 if (from
!= stop
&& c
== FETCH_CHAR (from
- 1))
1151 if (!++depth
) goto done2
;
1156 if (!--depth
) goto done2
;
1157 if (depth
< min_depth
)
1158 error ("Containing expression ends prematurely");
1162 if (!parse_sexp_ignore_comments
)
1165 if (code
!= SYNTAX (c
))
1166 /* For a two-char comment ender, we can assume
1167 it does end a comment. So scan back in a simple way. */
1169 if (from
!= stop
) from
--;
1172 if (SYNTAX (c
= FETCH_CHAR (from
)) == Scomment
1173 && SYNTAX_COMMENT_STYLE (c
) == comstyle
)
1182 if (SYNTAX_COMSTART_SECOND (c
)
1183 && SYNTAX_COMSTART_FIRST (FETCH_CHAR (from
))
1184 && SYNTAX_COMMENT_STYLE (c
) == comstyle
1185 && !char_quoted (from
))
1192 /* Look back, counting the parity of string-quotes,
1193 and recording the comment-starters seen.
1194 When we reach a safe place, assume that's not in a string;
1195 then step the main scan to the earliest comment-starter seen
1196 an even number of string quotes away from the safe place.
1198 OFROM[I] is position of the earliest comment-starter seen
1199 which is I+2X quotes from the comment-end.
1200 PARITY is current parity of quotes from the comment end. */
1203 char my_stringend
= 0;
1204 int string_lossage
= 0;
1205 int comment_end
= from
;
1206 int comstart_pos
= 0;
1207 int comstart_parity
= 0;
1208 int scanstart
= from
- 1;
1210 /* At beginning of range to scan, we're outside of strings;
1211 that determines quote parity to the comment-end. */
1212 while (from
!= stop
)
1214 /* Move back and examine a character. */
1217 c
= FETCH_CHAR (from
);
1220 /* If this char is the second of a 2-char comment sequence,
1221 back up and give the pair the appropriate syntax. */
1222 if (from
> stop
&& SYNTAX_COMEND_SECOND (c
)
1223 && SYNTAX_COMEND_FIRST (FETCH_CHAR (from
- 1)))
1227 c
= FETCH_CHAR (from
);
1230 /* If this char starts a 2-char comment start sequence,
1231 treat it like a 1-char comment starter. */
1232 if (from
< scanstart
&& SYNTAX_COMSTART_FIRST (c
)
1233 && SYNTAX_COMSTART_SECOND (FETCH_CHAR (from
+ 1))
1234 && comstyle
== SYNTAX_COMMENT_STYLE (FETCH_CHAR (from
+ 1)))
1237 /* Ignore escaped characters. */
1238 if (char_quoted (from
))
1241 /* Track parity of quotes. */
1242 if (code
== Sstring
)
1245 if (my_stringend
== 0)
1247 /* If we have two kinds of string delimiters.
1248 There's no way to grok this scanning backwards. */
1249 else if (my_stringend
!= c
)
1253 /* Record comment-starters according to that
1254 quote-parity to the comment-end. */
1255 if (code
== Scomment
)
1257 comstart_parity
= parity
;
1258 comstart_pos
= from
;
1261 /* If we find another earlier comment-ender,
1262 any comment-starts earlier than that don't count
1263 (because they go with the earlier comment-ender). */
1264 if (code
== Sendcomment
1265 && SYNTAX_COMMENT_STYLE (FETCH_CHAR (from
)) == comstyle
)
1268 /* Assume a defun-start point is outside of strings. */
1270 && (from
== stop
|| FETCH_CHAR (from
- 1) == '\n'))
1274 if (comstart_pos
== 0)
1276 /* If the earliest comment starter
1277 is followed by uniform paired string quotes or none,
1278 we know it can't be inside a string
1279 since if it were then the comment ender would be inside one.
1280 So it does start a comment. Skip back to it. */
1281 else if (comstart_parity
== 0 && !string_lossage
)
1282 from
= comstart_pos
;
1285 /* We had two kinds of string delimiters mixed up
1286 together. Decode this going forwards.
1287 Scan fwd from the previous comment ender
1288 to the one in question; this records where we
1289 last passed a comment starter. */
1290 struct lisp_parse_state state
;
1291 scan_sexps_forward (&state
, find_defun_start (comment_end
),
1292 comment_end
- 1, -10000, 0, Qnil
, 0);
1293 if (state
.incomment
)
1294 from
= state
.comstart
;
1296 /* We can't grok this as a comment; scan it normally. */
1303 stringterm
= FETCH_CHAR (from
);
1306 if (from
== stop
) goto lose
;
1307 if (!char_quoted (from
- 1)
1308 && stringterm
== FETCH_CHAR (from
- 1))
1313 if (!depth
&& sexpflag
) goto done2
;
1318 /* Reached start of buffer. Error if within object, return nil if between */
1319 if (depth
) goto lose
;
1330 XSETFASTINT (val
, from
);
1334 error ("Unbalanced parentheses");
1342 register enum syntaxcode code
;
1343 register int beg
= BEGV
;
1344 register int quoted
= 0;
1347 && ((code
= SYNTAX (FETCH_CHAR (pos
- 1))) == Scharquote
1348 || code
== Sescape
))
1349 pos
--, quoted
= !quoted
;
1353 DEFUN ("scan-lists", Fscan_lists
, Sscan_lists
, 3, 3, 0,
1354 "Scan from character number FROM by COUNT lists.\n\
1355 Returns the character number of the position thus found.\n\
1357 If DEPTH is nonzero, paren depth begins counting from that value,\n\
1358 only places where the depth in parentheses becomes zero\n\
1359 are candidates for stopping; COUNT such places are counted.\n\
1360 Thus, a positive value for DEPTH means go out levels.\n\
1362 Comments are ignored if `parse-sexp-ignore-comments' is non-nil.\n\
1364 If the beginning or end of (the accessible part of) the buffer is reached\n\
1365 and the depth is wrong, an error is signaled.\n\
1366 If the depth is right but the count is not used up, nil is returned.")
1367 (from
, count
, depth
)
1368 Lisp_Object from
, count
, depth
;
1370 CHECK_NUMBER (from
, 0);
1371 CHECK_NUMBER (count
, 1);
1372 CHECK_NUMBER (depth
, 2);
1374 return scan_lists (XINT (from
), XINT (count
), XINT (depth
), 0);
1377 DEFUN ("scan-sexps", Fscan_sexps
, Sscan_sexps
, 2, 2, 0,
1378 "Scan from character number FROM by COUNT balanced expressions.\n\
1379 If COUNT is negative, scan backwards.\n\
1380 Returns the character number of the position thus found.\n\
1382 Comments are ignored if `parse-sexp-ignore-comments' is non-nil.\n\
1384 If the beginning or end of (the accessible part of) the buffer is reached\n\
1385 in the middle of a parenthetical grouping, an error is signaled.\n\
1386 If the beginning or end is reached between groupings\n\
1387 but before count is used up, nil is returned.")
1389 Lisp_Object from
, count
;
1391 CHECK_NUMBER (from
, 0);
1392 CHECK_NUMBER (count
, 1);
1394 return scan_lists (XINT (from
), XINT (count
), 0, 1);
1397 DEFUN ("backward-prefix-chars", Fbackward_prefix_chars
, Sbackward_prefix_chars
,
1399 "Move point backward over any number of chars with prefix syntax.\n\
1400 This includes chars with \"quote\" or \"prefix\" syntax (' or p).")
1406 while (pos
> beg
&& !char_quoted (pos
- 1)
1407 && (SYNTAX (FETCH_CHAR (pos
- 1)) == Squote
1408 || SYNTAX_PREFIX (FETCH_CHAR (pos
- 1))))
1416 /* Parse forward from FROM to END,
1417 assuming that FROM has state OLDSTATE (nil means FROM is start of function),
1418 and return a description of the state of the parse at END.
1419 If STOPBEFORE is nonzero, stop at the start of an atom.
1420 If COMMENTSTOP is nonzero, stop at the start of a comment. */
1423 scan_sexps_forward (stateptr
, from
, end
, targetdepth
,
1424 stopbefore
, oldstate
, commentstop
)
1425 struct lisp_parse_state
*stateptr
;
1427 int end
, targetdepth
, stopbefore
;
1428 Lisp_Object oldstate
;
1431 struct lisp_parse_state state
;
1433 register enum syntaxcode code
;
1434 struct level
{ int last
, prev
; };
1435 struct level levelstart
[100];
1436 register struct level
*curlevel
= levelstart
;
1437 struct level
*endlevel
= levelstart
+ 100;
1439 register int depth
; /* Paren depth of current scanning location.
1440 level - levelstart equals this except
1441 when the depth becomes negative. */
1442 int mindepth
; /* Lowest DEPTH value seen. */
1443 int start_quoted
= 0; /* Nonzero means starting after a char quote */
1449 if (NILP (oldstate
))
1452 state
.instring
= -1;
1453 state
.incomment
= 0;
1454 state
.comstyle
= 0; /* comment style a by default */
1458 tem
= Fcar (oldstate
);
1464 oldstate
= Fcdr (oldstate
);
1465 oldstate
= Fcdr (oldstate
);
1466 oldstate
= Fcdr (oldstate
);
1467 tem
= Fcar (oldstate
);
1468 state
.instring
= !NILP (tem
) ? XINT (tem
) : -1;
1470 oldstate
= Fcdr (oldstate
);
1471 tem
= Fcar (oldstate
);
1472 state
.incomment
= !NILP (tem
);
1474 oldstate
= Fcdr (oldstate
);
1475 tem
= Fcar (oldstate
);
1476 start_quoted
= !NILP (tem
);
1478 /* if the eight element of the list is nil, we are in comment
1479 style a. if it is non-nil, we are in comment style b */
1480 oldstate
= Fcdr (oldstate
);
1481 oldstate
= Fcdr (oldstate
);
1482 tem
= Fcar (oldstate
);
1483 state
.comstyle
= !NILP (tem
);
1488 curlevel
->prev
= -1;
1489 curlevel
->last
= -1;
1491 /* Enter the loop at a place appropriate for initial state. */
1493 if (state
.incomment
) goto startincomment
;
1494 if (state
.instring
>= 0)
1496 if (start_quoted
) goto startquotedinstring
;
1499 if (start_quoted
) goto startquoted
;
1503 code
= SYNTAX (FETCH_CHAR (from
));
1505 if (code
== Scomment
)
1506 state
.comstart
= from
-1;
1508 else if (from
< end
&& SYNTAX_COMSTART_FIRST (FETCH_CHAR (from
- 1))
1509 && SYNTAX_COMSTART_SECOND (FETCH_CHAR (from
)))
1511 /* Record the comment style we have entered so that only
1512 the comment-end sequence of the same style actually
1513 terminates the comment section. */
1515 state
.comstyle
= SYNTAX_COMMENT_STYLE (FETCH_CHAR (from
));
1516 state
.comstart
= from
-1;
1520 if (SYNTAX_PREFIX (FETCH_CHAR (from
- 1)))
1522 switch (SWITCH_ENUM_CAST (code
))
1526 if (stopbefore
) goto stop
; /* this arg means stop at sexp start */
1527 curlevel
->last
= from
- 1;
1529 if (from
== end
) goto endquoted
;
1532 /* treat following character as a word constituent */
1535 if (stopbefore
) goto stop
; /* this arg means stop at sexp start */
1536 curlevel
->last
= from
- 1;
1540 switch (SWITCH_ENUM_CAST (SYNTAX (FETCH_CHAR (from
))))
1545 if (from
== end
) goto endquoted
;
1557 curlevel
->prev
= curlevel
->last
;
1565 /* Enter the loop in the middle so that we find
1566 a 2-char comment ender if we start in the middle of it. */
1567 prev
= FETCH_CHAR (from
- 1);
1568 goto startincomment_1
;
1570 /* At beginning of buffer, enter the loop the ordinary way. */
1573 state
.incomment
= 1;
1578 if (from
== end
) goto done
;
1579 prev
= FETCH_CHAR (from
);
1580 if (SYNTAX (prev
) == Sendcomment
1581 && SYNTAX_COMMENT_STYLE (prev
) == state
.comstyle
)
1582 /* Only terminate the comment section if the endcomment
1583 of the same style as the start sequence has been
1588 if (from
< end
&& SYNTAX_COMEND_FIRST (prev
)
1589 && SYNTAX_COMEND_SECOND (FETCH_CHAR (from
))
1590 && SYNTAX_COMMENT_STYLE (prev
) == state
.comstyle
)
1591 /* Only terminate the comment section if the end-comment
1592 sequence of the same style as the start sequence has
1593 been encountered. */
1596 state
.incomment
= 0;
1597 state
.comstyle
= 0; /* reset the comment style */
1601 if (stopbefore
) goto stop
; /* this arg means stop at sexp start */
1603 /* curlevel++->last ran into compiler bug on Apollo */
1604 curlevel
->last
= from
- 1;
1605 if (++curlevel
== endlevel
)
1606 error ("Nesting too deep for parser");
1607 curlevel
->prev
= -1;
1608 curlevel
->last
= -1;
1609 if (targetdepth
== depth
) goto done
;
1614 if (depth
< mindepth
)
1616 if (curlevel
!= levelstart
)
1618 curlevel
->prev
= curlevel
->last
;
1619 if (targetdepth
== depth
) goto done
;
1623 if (stopbefore
) goto stop
; /* this arg means stop at sexp start */
1624 curlevel
->last
= from
- 1;
1625 state
.instring
= FETCH_CHAR (from
- 1);
1629 if (from
>= end
) goto done
;
1630 if (FETCH_CHAR (from
) == state
.instring
) break;
1631 switch (SWITCH_ENUM_CAST (SYNTAX (FETCH_CHAR (from
))))
1636 startquotedinstring
:
1637 if (from
>= end
) goto endquoted
;
1641 state
.instring
= -1;
1642 curlevel
->prev
= curlevel
->last
;
1652 stop
: /* Here if stopping before start of sexp. */
1653 from
--; /* We have just fetched the char that starts it; */
1654 goto done
; /* but return the position before it. */
1659 state
.depth
= depth
;
1660 state
.mindepth
= mindepth
;
1661 state
.thislevelstart
= curlevel
->prev
;
1662 state
.prevlevelstart
1663 = (curlevel
== levelstart
) ? -1 : (curlevel
- 1)->last
;
1664 state
.location
= from
;
1670 /* This comment supplies the doc string for parse-partial-sexp,
1671 for make-docfile to see. We cannot put this in the real DEFUN
1672 due to limits in the Unix cpp.
1674 DEFUN ("parse-partial-sexp", Ffoo, Sfoo, 2, 6, 0,
1675 "Parse Lisp syntax starting at FROM until TO; return status of parse at TO.\n\
1676 Parsing stops at TO or when certain criteria are met;\n\
1677 point is set to where parsing stops.\n\
1678 If fifth arg STATE is omitted or nil,\n\
1679 parsing assumes that FROM is the beginning of a function.\n\
1680 Value is a list of eight elements describing final state of parsing:\n\
1681 0. depth in parens.\n\
1682 1. character address of start of innermost containing list; nil if none.\n\
1683 2. character address of start of last complete sexp terminated.\n\
1684 3. non-nil if inside a string.\n\
1685 (it is the character that will terminate the string.)\n\
1686 4. t if inside a comment.\n\
1687 5. t if following a quote character.\n\
1688 6. the minimum paren-depth encountered during this scan.\n\
1689 7. t if in a comment of style `b'.\n\
1690 If third arg TARGETDEPTH is non-nil, parsing stops if the depth\n\
1691 in parentheses becomes equal to TARGETDEPTH.\n\
1692 Fourth arg STOPBEFORE non-nil means stop when come to\n\
1693 any character that starts a sexp.\n\
1694 Fifth arg STATE is an eight-list like what this function returns.\n\
1695 It is used to initialize the state of the parse. Its second and third
1696 elements are ignored.
1697 Sixth args COMMENTSTOP non-nil means stop at the start of a comment.")
1698 (from, to, targetdepth, stopbefore, state, commentstop)
1701 DEFUN ("parse-partial-sexp", Fparse_partial_sexp
, Sparse_partial_sexp
, 2, 6, 0,
1702 0 /* See immediately above */)
1703 (from
, to
, targetdepth
, stopbefore
, oldstate
, commentstop
)
1704 Lisp_Object from
, to
, targetdepth
, stopbefore
, oldstate
, commentstop
;
1706 struct lisp_parse_state state
;
1709 if (!NILP (targetdepth
))
1711 CHECK_NUMBER (targetdepth
, 3);
1712 target
= XINT (targetdepth
);
1715 target
= -100000; /* We won't reach this depth */
1717 validate_region (&from
, &to
);
1718 scan_sexps_forward (&state
, XINT (from
), XINT (to
),
1719 target
, !NILP (stopbefore
), oldstate
,
1720 !NILP (commentstop
));
1722 SET_PT (state
.location
);
1724 return Fcons (make_number (state
.depth
),
1725 Fcons (state
.prevlevelstart
< 0 ? Qnil
: make_number (state
.prevlevelstart
),
1726 Fcons (state
.thislevelstart
< 0 ? Qnil
: make_number (state
.thislevelstart
),
1727 Fcons (state
.instring
>= 0 ? make_number (state
.instring
) : Qnil
,
1728 Fcons (state
.incomment
? Qt
: Qnil
,
1729 Fcons (state
.quoted
? Qt
: Qnil
,
1730 Fcons (make_number (state
.mindepth
),
1731 Fcons (state
.comstyle
? Qt
: Qnil
,
1740 /* This has to be done here, before we call Fmake_char_table. */
1741 Qsyntax_table
= intern ("syntax-table");
1742 staticpro (&Qsyntax_table
);
1744 /* Intern this now in case it isn't already done.
1745 Setting this variable twice is harmless.
1746 But don't staticpro it here--that is done in alloc.c. */
1747 Qchar_table_extra_slots
= intern ("char-table-extra-slots");
1749 /* Now we are ready to set up this property, so we can
1750 create syntax tables. */
1751 Fput (Qsyntax_table
, Qchar_table_extra_slots
, make_number (0));
1753 temp
= Fcons (make_number ((int) Swhitespace
), Qnil
);
1755 Vstandard_syntax_table
= Fmake_char_table (Qsyntax_table
, temp
);
1757 temp
= Fcons (make_number ((int) Sword
), Qnil
);
1758 for (i
= 'a'; i
<= 'z'; i
++)
1759 SET_RAW_SYNTAX_ENTRY (Vstandard_syntax_table
, i
, temp
);
1760 for (i
= 'A'; i
<= 'Z'; i
++)
1761 SET_RAW_SYNTAX_ENTRY (Vstandard_syntax_table
, i
, temp
);
1762 for (i
= '0'; i
<= '9'; i
++)
1763 SET_RAW_SYNTAX_ENTRY (Vstandard_syntax_table
, i
, temp
);
1765 SET_RAW_SYNTAX_ENTRY (Vstandard_syntax_table
, '$', temp
);
1766 SET_RAW_SYNTAX_ENTRY (Vstandard_syntax_table
, '%', temp
);
1768 SET_RAW_SYNTAX_ENTRY (Vstandard_syntax_table
, '(',
1769 Fcons (make_number (Sopen
), make_number (')')));
1770 SET_RAW_SYNTAX_ENTRY (Vstandard_syntax_table
, ')',
1771 Fcons (make_number (Sclose
), make_number ('(')));
1772 SET_RAW_SYNTAX_ENTRY (Vstandard_syntax_table
, '[',
1773 Fcons (make_number (Sopen
), make_number (']')));
1774 SET_RAW_SYNTAX_ENTRY (Vstandard_syntax_table
, ']',
1775 Fcons (make_number (Sclose
), make_number ('[')));
1776 SET_RAW_SYNTAX_ENTRY (Vstandard_syntax_table
, '{',
1777 Fcons (make_number (Sopen
), make_number ('}')));
1778 SET_RAW_SYNTAX_ENTRY (Vstandard_syntax_table
, '}',
1779 Fcons (make_number (Sclose
), make_number ('{')));
1780 SET_RAW_SYNTAX_ENTRY (Vstandard_syntax_table
, '"',
1781 Fcons (make_number ((int) Sstring
), Qnil
));
1782 SET_RAW_SYNTAX_ENTRY (Vstandard_syntax_table
, '\\',
1783 Fcons (make_number ((int) Sescape
), Qnil
));
1785 temp
= Fcons (make_number ((int) Ssymbol
), Qnil
);
1786 for (i
= 0; i
< 10; i
++)
1787 SET_RAW_SYNTAX_ENTRY (Vstandard_syntax_table
, "_-+*/&|<>="[i
], temp
);
1789 temp
= Fcons (make_number ((int) Spunct
), Qnil
);
1790 for (i
= 0; i
< 12; i
++)
1791 SET_RAW_SYNTAX_ENTRY (Vstandard_syntax_table
, ".,;:?!#@~^'`"[i
], temp
);
1796 Qsyntax_table_p
= intern ("syntax-table-p");
1797 staticpro (&Qsyntax_table_p
);
1799 DEFVAR_BOOL ("parse-sexp-ignore-comments", &parse_sexp_ignore_comments
,
1800 "Non-nil means `forward-sexp', etc., should treat comments as whitespace.");
1802 words_include_escapes
= 0;
1803 DEFVAR_BOOL ("words-include-escapes", &words_include_escapes
,
1804 "Non-nil means `forward-word', etc., should treat escape chars part of words.");
1806 defsubr (&Ssyntax_table_p
);
1807 defsubr (&Ssyntax_table
);
1808 defsubr (&Sstandard_syntax_table
);
1809 defsubr (&Scopy_syntax_table
);
1810 defsubr (&Sset_syntax_table
);
1811 defsubr (&Schar_syntax
);
1812 defsubr (&Smatching_paren
);
1813 defsubr (&Smodify_syntax_entry
);
1814 defsubr (&Sdescribe_syntax
);
1816 defsubr (&Sforward_word
);
1818 defsubr (&Sforward_comment
);
1819 defsubr (&Sscan_lists
);
1820 defsubr (&Sscan_sexps
);
1821 defsubr (&Sbackward_prefix_chars
);
1822 defsubr (&Sparse_partial_sexp
);