#include "commands.h"
#include "buffer.h"
#include "charset.h"
+#include "keymap.h"
/* Make syntax table lookup grant data in gl_state. */
#define SYNTAX_ENTRY_VIA_PROPERTY
if (init)
{
+ gl_state.old_prop = Qnil;
gl_state.start = gl_state.b_property;
gl_state.stop = gl_state.e_property;
- gl_state.forward_i = interval_of (charpos, object);
- i = gl_state.backward_i = gl_state.forward_i;
- gl_state.left_ok = gl_state.right_ok = 1;
+ i = interval_of (charpos, object);
+ gl_state.backward_i = gl_state.forward_i = i;
invalidate = 0;
if (NULL_INTERVAL_P (i))
return;
/* interval_of updates only ->position of the return value, so
update the parents manually to speed up update_interval. */
- while (!NULL_PARENT (i))
+ while (!NULL_PARENT (i))
{
if (AM_RIGHT_CHILD (i))
INTERVAL_PARENT (i)->position = i->position
i = INTERVAL_PARENT (i);
}
i = gl_state.forward_i;
- gl_state.b_property = i->position - 1 - gl_state.offset;
+ gl_state.b_property = i->position - gl_state.offset;
gl_state.e_property = INTERVAL_LAST_POS (i) - gl_state.offset;
goto update;
}
oldi = i = count > 0 ? gl_state.forward_i : gl_state.backward_i;
- /* We are guarantied to be called with CHARPOS either in i,
+ /* We are guaranteed to be called with CHARPOS either in i,
or further off. */
if (NULL_INTERVAL_P (i))
error ("Error in syntax_table logic for to-the-end intervals");
error ("Error in syntax_table logic for intervals <-");
/* Update the interval. */
i = update_interval (i, charpos);
- if (oldi->position != INTERVAL_LAST_POS (i))
+ if (INTERVAL_LAST_POS (i) != gl_state.b_property)
{
invalidate = 0;
- gl_state.right_ok = 1; /* Invalidate the other end. */
gl_state.forward_i = i;
gl_state.e_property = INTERVAL_LAST_POS (i) - gl_state.offset;
}
- }
+ }
else if (charpos >= INTERVAL_LAST_POS (i)) /* Move right. */
{
if (count < 0)
error ("Error in syntax_table logic for intervals ->");
/* Update the interval. */
i = update_interval (i, charpos);
- if (i->position != INTERVAL_LAST_POS (oldi))
+ if (i->position != gl_state.e_property)
{
invalidate = 0;
- gl_state.left_ok = 1; /* Invalidate the other end. */
gl_state.backward_i = i;
- gl_state.b_property = i->position - 1 - gl_state.offset;
+ gl_state.b_property = i->position - gl_state.offset;
}
}
- else if (count > 0 ? gl_state.right_ok : gl_state.left_ok)
- {
- /* We do not need to recalculate tmp_table. */
- tmp_table = gl_state.old_prop;
- }
update:
tmp_table = textget (i->plist, Qsyntax_table);
if (invalidate)
invalidate = !EQ (tmp_table, gl_state.old_prop); /* Need to invalidate? */
- if (invalidate) /* Did not get to adjacent interval. */
- { /* with the same table => */
- /* invalidate the old range. */
+ if (invalidate) /* Did not get to adjacent interval. */
+ { /* with the same table => */
+ /* invalidate the old range. */
if (count > 0)
{
gl_state.backward_i = i;
- gl_state.left_ok = 1; /* Invalidate the other end. */
- gl_state.b_property = i->position - 1 - gl_state.offset;
- }
- else
+ gl_state.b_property = i->position - gl_state.offset;
+ }
+ else
{
- gl_state.forward_i = i;
- gl_state.right_ok = 1; /* Invalidate the other end. */
+ gl_state.forward_i = i;
gl_state.e_property = INTERVAL_LAST_POS (i) - gl_state.offset;
}
}
- gl_state.current_syntax_table = tmp_table;
- gl_state.old_prop = tmp_table;
- if (EQ (Fsyntax_table_p (tmp_table), Qt))
+ if (!EQ (tmp_table, gl_state.old_prop))
{
- gl_state.use_global = 0;
- }
- else if (CONSP (tmp_table))
- {
- gl_state.use_global = 1;
- gl_state.global_code = tmp_table;
- }
- else
- {
- gl_state.use_global = 0;
- gl_state.current_syntax_table = current_buffer->syntax_table;
+ gl_state.current_syntax_table = tmp_table;
+ gl_state.old_prop = tmp_table;
+ if (EQ (Fsyntax_table_p (tmp_table), Qt))
+ {
+ gl_state.use_global = 0;
+ }
+ else if (CONSP (tmp_table))
+ {
+ gl_state.use_global = 1;
+ gl_state.global_code = tmp_table;
+ }
+ else
+ {
+ gl_state.use_global = 0;
+ gl_state.current_syntax_table = current_buffer->syntax_table;
+ }
}
while (!NULL_INTERVAL_P (i))
if (cnt && !EQ (tmp_table, textget (i->plist, Qsyntax_table)))
{
if (count > 0)
- gl_state.right_ok = 0;
- else
- gl_state.left_ok = 0;
- break;
+ {
+ gl_state.e_property = i->position - gl_state.offset;
+ gl_state.forward_i = i;
+ }
+ else
+ {
+ gl_state.b_property = i->position + LENGTH (i) - gl_state.offset;
+ gl_state.backward_i = i;
+ }
+ return;
}
else if (cnt == INTERVALS_AT_ONCE)
{
if (count > 0)
- gl_state.right_ok = 1;
- else
- gl_state.left_ok = 1;
- break;
+ {
+ gl_state.e_property = i->position + LENGTH (i) - gl_state.offset;
+ gl_state.forward_i = i;
+ }
+ else
+ {
+ gl_state.b_property = i->position - gl_state.offset;
+ gl_state.backward_i = i;
+ }
+ return;
}
cnt++;
i = count > 0 ? next_interval (i) : previous_interval (i);
}
- if (NULL_INTERVAL_P (i))
- { /* This property goes to the end. */
- if (count > 0)
- gl_state.e_property = gl_state.stop;
- else
- gl_state.b_property = gl_state.start;
- }
- else
- {
- if (count > 0)
- {
- gl_state.e_property = i->position - gl_state.offset;
- gl_state.forward_i = i;
- }
- else
- {
- gl_state.b_property = i->position + LENGTH (i) - 1 - gl_state.offset;
- gl_state.backward_i = i;
- }
- }
+ eassert (NULL_INTERVAL_P (i)); /* This property goes to the end. */
+ if (count > 0)
+ gl_state.e_property = gl_state.stop;
+ else
+ gl_state.b_property = gl_state.start;
}
\f
/* Returns TRUE if char at CHARPOS is quoted.
return bytepos;
}
\f
-/* Find a defun-start that is the last one before POS (or nearly the last).
- We record what we find, so that another call in the same area
- can return the same value right away.
+/* Return a defun-start position before before POS and not too far before.
+ It should be the last one before POS, or nearly the last.
+
+ When open_paren_in_column_0_is_defun_start is nonzero,
+ the beginning of every line is treated as a defun-start.
+
+ We record the information about where the scan started
+ and what its result was, so that another call in the same area
+ can return the same value very quickly.
There is no promise at which position the global syntax data is
valid on return from the subroutine, so the caller should explicitly
/* Return the SYNTAX_COMSTART_FIRST of the character before POS, POS_BYTE. */
-static int
-prev_char_comstart_first (pos, pos_byte)
- int pos, pos_byte;
-{
- int c, val;
-
- DEC_BOTH (pos, pos_byte);
- UPDATE_SYNTAX_TABLE_BACKWARD (pos);
- c = FETCH_CHAR (pos_byte);
- val = SYNTAX_COMSTART_FIRST (c);
- UPDATE_SYNTAX_TABLE_FORWARD (pos + 1);
- return val;
-}
+/* static int
+ * prev_char_comstart_first (pos, pos_byte)
+ * int pos, pos_byte;
+ * {
+ * int c, val;
+ *
+ * DEC_BOTH (pos, pos_byte);
+ * UPDATE_SYNTAX_TABLE_BACKWARD (pos);
+ * c = FETCH_CHAR (pos_byte);
+ * val = SYNTAX_COMSTART_FIRST (c);
+ * UPDATE_SYNTAX_TABLE_FORWARD (pos + 1);
+ * return val;
+ * } */
/* Checks whether charpos FROM is at the end of a comment.
FROM_BYTE is the bytepos corresponding to FROM.
OFROM[I] is position of the earliest comment-starter seen
which is I+2X quotes from the comment-end.
PARITY is current parity of quotes from the comment end. */
- int parity = 0;
- int my_stringend = 0;
+ int string_style = -1; /* Presumed outside of any string. */
int string_lossage = 0;
+ /* Not a real lossage: indicates that we have passed a matching comment
+ starter plus an non-matching comment-ender, meaning that any matching
+ comment-starter we might see later could be a false positive (hidden
+ inside another comment).
+ Test case: { a (* b } c (* d *) */
+ int comment_lossage = 0;
int comment_end = from;
int comment_end_byte = from_byte;
int comstart_pos = 0;
int comstart_byte;
- /* Value that PARITY had, when we reached the position
- in COMSTART_POS. */
- int comstart_parity = 0;
- int scanstart = from - 1;
/* Place where the containing defun starts,
or 0 if we didn't come across it yet. */
int defun_start = 0;
register enum syntaxcode code;
int nesting = 1; /* current comment nesting */
int c;
+ int syntax = 0;
+
+ /* FIXME: A }} comment-ender style leads to incorrect behavior
+ in the case of {{ c }}} because we ignore the last two chars which are
+ assumed to be comment-enders although they aren't. */
/* At beginning of range to scan, we're outside of strings;
that determines quote parity to the comment-end. */
while (from != stop)
{
- int temp_byte;
+ int temp_byte, prev_syntax;
+ int com2start, com2end;
/* Move back and examine a character. */
DEC_BOTH (from, from_byte);
UPDATE_SYNTAX_TABLE_BACKWARD (from);
+ prev_syntax = syntax;
c = FETCH_CHAR (from_byte);
+ syntax = SYNTAX_WITH_FLAGS (c);
code = SYNTAX (c);
- /* If this char is the second of a 2-char comment end sequence,
- back up and give the pair the appropriate syntax. */
- if (from > stop && SYNTAX_COMEND_SECOND (c)
- && prev_char_comend_first (from, from_byte))
+ /* Check for 2-char comment markers. */
+ com2start = (SYNTAX_FLAGS_COMSTART_FIRST (syntax)
+ && SYNTAX_FLAGS_COMSTART_SECOND (prev_syntax)
+ && comstyle == SYNTAX_FLAGS_COMMENT_STYLE (prev_syntax)
+ && (SYNTAX_FLAGS_COMMENT_NESTED (prev_syntax)
+ || SYNTAX_FLAGS_COMMENT_NESTED (syntax)) == comnested);
+ com2end = (SYNTAX_FLAGS_COMEND_FIRST (syntax)
+ && SYNTAX_FLAGS_COMEND_SECOND (prev_syntax));
+
+ /* Nasty cases with overlapping 2-char comment markers:
+ - snmp-mode: -- c -- foo -- c --
+ --- c --
+ ------ c --
+ - c-mode: *||*
+ |* *|* *|
+ |*| |* |*|
+ /// */
+
+ /* If a 2-char comment sequence partly overlaps with another,
+ we don't try to be clever. */
+ if (from > stop && (com2end || com2start))
{
- code = Sendcomment;
- DEC_BOTH (from, from_byte);
- UPDATE_SYNTAX_TABLE_BACKWARD (from);
- c = FETCH_CHAR (from_byte);
- }
-
- /* If this char starts a 2-char comment start sequence,
- treat it like a 1-char comment starter. */
- if (from < scanstart && SYNTAX_COMSTART_FIRST (c))
- {
- temp_byte = inc_bytepos (from_byte);
- UPDATE_SYNTAX_TABLE_FORWARD (from + 1);
- if (SYNTAX_COMSTART_SECOND (FETCH_CHAR (temp_byte))
- && comstyle == SYNTAX_COMMENT_STYLE (FETCH_CHAR (temp_byte)))
- code = Scomment;
- UPDATE_SYNTAX_TABLE_BACKWARD (from);
+ int next = from, next_byte = from_byte, next_c, next_syntax;
+ DEC_BOTH (next, next_byte);
+ UPDATE_SYNTAX_TABLE_BACKWARD (next);
+ next_c = FETCH_CHAR (next_byte);
+ next_syntax = SYNTAX_WITH_FLAGS (next_c);
+ if (((com2start || comnested)
+ && SYNTAX_FLAGS_COMEND_SECOND (syntax)
+ && SYNTAX_FLAGS_COMEND_FIRST (next_syntax))
+ || ((com2end || comnested)
+ && SYNTAX_FLAGS_COMSTART_SECOND (syntax)
+ && comstyle == SYNTAX_FLAGS_COMMENT_STYLE (syntax)
+ && SYNTAX_FLAGS_COMSTART_FIRST (next_syntax)))
+ goto lossage;
+ /* UPDATE_SYNTAX_TABLE_FORWARD (next + 1); */
}
- else if (code == Scomment && comstyle != SYNTAX_COMMENT_STYLE (c))
- /* Ignore comment starters of a different style. */
+
+ if (com2start && comstart_pos == 0)
+ /* We're looking at a comment starter. But it might be a comment
+ ender as well (see snmp-mode). The first time we see one, we
+ need to consider it as a comment starter,
+ and the subsequent times as a comment ender. */
+ com2end = 0;
+
+ /* Turn a 2-char comment sequences into the appropriate syntax. */
+ if (com2end)
+ code = Sendcomment;
+ else if (com2start)
+ code = Scomment;
+ /* Ignore comment starters of a different style. */
+ else if (code == Scomment
+ && (comstyle != SYNTAX_FLAGS_COMMENT_STYLE (syntax)
+ || SYNTAX_FLAGS_COMMENT_NESTED (syntax) != comnested))
continue;
/* Ignore escaped characters, except comment-enders. */
if (code != Sendcomment && char_quoted (from, from_byte))
continue;
- /* Track parity of quotes. */
- if (code == Sstring)
- {
- parity ^= 1;
- if (my_stringend == 0)
- my_stringend = c;
- /* If we have two kinds of string delimiters.
- There's no way to grok this scanning backwards. */
- else if (my_stringend != c)
- string_lossage = 1;
- }
-
- if (code == Sstring_fence || code == Scomment_fence)
+ switch (code)
{
- parity ^= 1;
- if (my_stringend == 0)
- my_stringend
- = code == Sstring_fence ? ST_STRING_STYLE : ST_COMMENT_STYLE;
- /* If we have two kinds of string delimiters.
- There's no way to grok this scanning backwards. */
- else if (my_stringend != (code == Sstring_fence
- ? ST_STRING_STYLE : ST_COMMENT_STYLE))
+ case Sstring_fence:
+ case Scomment_fence:
+ c = (code == Sstring_fence ? ST_STRING_STYLE : ST_COMMENT_STYLE);
+ case Sstring:
+ /* Track parity of quotes. */
+ if (string_style == -1)
+ /* Entering a string. */
+ string_style = c;
+ else if (string_style == c)
+ /* Leaving the string. */
+ string_style = -1;
+ else
+ /* If we have two kinds of string delimiters.
+ There's no way to grok this scanning backwards. */
string_lossage = 1;
- }
+ break;
+
+ case Scomment:
+ /* We've already checked that it is the relevant comstyle. */
+ if (string_style != -1 || comment_lossage || string_lossage)
+ /* There are odd string quotes involved, so let's be careful.
+ Test case in Pascal: " { " a { " } */
+ goto lossage;
- if (code == Scomment)
- /* We've already checked that it is the relevant comstyle. */
- {
- if (comnested && --nesting <= 0 && parity == 0 && !string_lossage)
+ if (!comnested)
+ {
+ /* Record best comment-starter so far. */
+ comstart_pos = from;
+ comstart_byte = from_byte;
+ }
+ else if (--nesting <= 0)
/* nested comments have to be balanced, so we don't need to
keep looking for earlier ones. We use here the same (slightly
incorrect) reasoning as below: since it is followed by uniform
paired string quotes, this comment-start has to be outside of
strings, else the comment-end itself would be inside a string. */
goto done;
+ break;
- /* Record comment-starters according to that
- quote-parity to the comment-end. */
- comstart_parity = parity;
- comstart_pos = from;
- comstart_byte = from_byte;
- }
+ case Sendcomment:
+ if (SYNTAX_FLAGS_COMMENT_STYLE (syntax) == comstyle
+ && (SYNTAX_FLAGS_COMMENT_NESTED (prev_syntax)
+ || SYNTAX_FLAGS_COMMENT_NESTED (syntax)) == comnested)
+ /* This is the same style of comment ender as ours. */
+ {
+ if (comnested)
+ nesting++;
+ else
+ /* Anything before that can't count because it would match
+ this comment-ender rather than ours. */
+ from = stop; /* Break out of the loop. */
+ }
+ else if (comstart_pos != 0 || c != '\n')
+ /* We're mixing comment styles here, so we'd better be careful.
+ The (comstart_pos != 0 || c != '\n') check is not quite correct
+ (we should just always set comment_lossage), but removing it
+ would imply that any multiline comment in C would go through
+ lossage, which seems overkill.
+ The failure should only happen in the rare cases such as
+ { (* } *) */
+ comment_lossage = 1;
+ break;
- /* If we find another earlier comment-ender,
- any comment-starts earlier than that don't count
- (because they go with the earlier comment-ender). */
- if (code == Sendcomment
- && SYNTAX_COMMENT_STYLE (FETCH_CHAR (from_byte)) == comstyle)
- {
- if (comnested)
- nesting++;
- else
- break;
- }
+ case Sopen:
+ /* Assume a defun-start point is outside of strings. */
+ if (open_paren_in_column_0_is_defun_start
+ && (from == stop
+ || (temp_byte = dec_bytepos (from_byte),
+ FETCH_CHAR (temp_byte) == '\n')))
+ {
+ defun_start = from;
+ defun_start_byte = from_byte;
+ from = stop; /* Break out of the loop. */
+ }
+ break;
- /* Assume a defun-start point is outside of strings. */
- if (code == Sopen
- && (from == stop
- || (temp_byte = dec_bytepos (from_byte),
- FETCH_CHAR (temp_byte) == '\n')))
- {
- defun_start = from;
- defun_start_byte = from_byte;
+ default:
break;
}
}
from_byte = comment_end_byte;
UPDATE_SYNTAX_TABLE_FORWARD (comment_end - 1);
}
- /* If the earliest comment starter
- is followed by uniform paired string quotes or none,
- we know it can't be inside a string
- since if it were then the comment ender would be inside one.
- So it does start a comment. Skip back to it. */
- else if (!comnested && comstart_parity == 0 && !string_lossage)
+ /* If comstart_pos is set and we get here (ie. didn't jump to `lossage'
+ or `done'), then we've found the beginning of the non-nested comment. */
+ else if (1) /* !comnested */
{
from = comstart_pos;
from_byte = comstart_byte;
}
else
{
+ struct lisp_parse_state state;
+ lossage:
/* We had two kinds of string delimiters mixed up
together. Decode this going forwards.
- Scan fwd from the previous comment ender
+ Scan fwd from a known safe place (beginning-of-defun)
to the one in question; this records where we
last passed a comment starter. */
- struct lisp_parse_state state;
/* If we did not already find the defun start, find it now. */
if (defun_start == 0)
{
defun_start = find_defun_start (comment_end, comment_end_byte);
defun_start_byte = find_start_value_byte;
}
- scan_sexps_forward (&state,
- defun_start, defun_start_byte,
- comment_end - 1, -10000, 0, Qnil, 0);
- if (state.incomment)
- {
- /* scan_sexps_forward changed the direction of search in
- global variables, so we need to update it completely. */
-
- from = state.comstr_start;
- }
- else
+ do
{
- from = comment_end;
- }
+ scan_sexps_forward (&state,
+ defun_start, defun_start_byte,
+ comment_end, -10000, 0, Qnil, 0);
+ defun_start = comment_end;
+ if (state.incomment == (comnested ? 1 : -1)
+ && state.comstyle == comstyle)
+ from = state.comstr_start;
+ else
+ {
+ from = comment_end;
+ if (state.incomment)
+ /* If comment_end is inside some other comment, maybe ours
+ is nested, so we need to try again from within the
+ surrounding comment. Example: { a (* " *) */
+ {
+ /* FIXME: We should advance by one or two chars. */
+ defun_start = state.comstr_start + 2;
+ defun_start_byte = CHAR_TO_BYTE (defun_start);
+ }
+ }
+ } while (defun_start < comment_end);
+
from_byte = CHAR_TO_BYTE (from);
UPDATE_SYNTAX_TABLE_FORWARD (from - 1);
}
return Qnil;
}
-/* This comment supplies the doc string for modify-syntax-entry,
- for make-docfile to see. We cannot put this in the real DEFUN
- due to limits in the Unix cpp.
-
-DEFUN ("modify-syntax-entry", foo, bar, 2, 3, 0,
- "Set syntax for character CHAR according to string S.\n\
-The syntax is changed only for table TABLE, which defaults to\n\
- the current buffer's syntax table.\n\
-The first character of S should be one of the following:\n\
- Space or - whitespace syntax. w word constituent.\n\
- _ symbol constituent. . punctuation.\n\
- ( open-parenthesis. ) close-parenthesis.\n\
- \" string quote. \\ escape.\n\
- $ paired delimiter. ' expression quote or prefix operator.\n\
- < comment starter. > comment ender.\n\
- / character-quote. @ inherit from `standard-syntax-table'.\n\
-\n\
-Only single-character comment start and end sequences are represented thus.\n\
-Two-character sequences are represented as described below.\n\
-The second character of S is the matching parenthesis,\n\
- used only if the first character is `(' or `)'.\n\
-Any additional characters are flags.\n\
-Defined flags are the characters 1, 2, 3, 4, b, p, and n.\n\
- 1 means CHAR is the start of a two-char comment start sequence.\n\
- 2 means CHAR is the second character of such a sequence.\n\
- 3 means CHAR is the start of a two-char comment end sequence.\n\
- 4 means CHAR is the second character of such a sequence.\n\
-\n\
-There can be up to two orthogonal comment sequences. This is to support\n\
-language modes such as C++. By default, all comment sequences are of style\n\
-a, but you can set the comment sequence style to b (on the second character\n\
-of a comment-start, or the first character of a comment-end sequence) using\n\
-this flag:\n\
- b means CHAR is part of comment sequence b.\n\
- n means CHAR is part of a nestable comment sequence.\n\
-\n\
- p means CHAR is a prefix character for `backward-prefix-chars';\n\
- such characters are treated as whitespace when they occur\n\
- between expressions.")
- (char, s, table)
-*/
-
-DEFUN ("modify-syntax-entry", Fmodify_syntax_entry, Smodify_syntax_entry, 2, 3,
- /* I really don't know why this is interactive
- help-form should at least be made useful whilst reading the second arg
- */
- "cSet syntax for character: \nsSet syntax for %s to: ",
- 0 /* See immediately above */)
- (c, newentry, syntax_table)
- Lisp_Object c, newentry, syntax_table;
+DEFUN ("string-to-syntax", Fstring_to_syntax, Sstring_to_syntax, 1, 1, 0,
+ "Convert a syntax specification STRING into syntax cell form.\n\
+STRING should be a string as it is allowed as argument of\n\
+`modify-syntax-entry'. Value is the equivalent cons cell\n\
+\(CODE . MATCHING-CHAR) that can be used as value of a `syntax-table'\n\
+text property.")
+ (string)
+ Lisp_Object string;
{
register unsigned char *p;
register enum syntaxcode code;
int val;
Lisp_Object match;
- CHECK_NUMBER (c, 0);
- CHECK_STRING (newentry, 1);
-
- if (NILP (syntax_table))
- syntax_table = current_buffer->syntax_table;
- else
- check_syntax_table (syntax_table);
+ CHECK_STRING (string, 0);
- p = XSTRING (newentry)->data;
+ p = XSTRING (string)->data;
code = (enum syntaxcode) syntax_spec_code[*p++];
if (((int) code & 0377) == 0377)
error ("invalid syntax description letter: %c", p[-1]);
if (code == Sinherit)
- {
- SET_RAW_SYNTAX_ENTRY (syntax_table, XINT (c), Qnil);
- return Qnil;
- }
+ return Qnil;
if (*p)
{
int len;
int character = (STRING_CHAR_AND_LENGTH
- (p, STRING_BYTES (XSTRING (newentry)) - 1, len));
+ (p, STRING_BYTES (XSTRING (string)) - 1, len));
XSETINT (match, character);
if (XFASTINT (match) == ' ')
match = Qnil;
}
if (val < XVECTOR (Vsyntax_code_object)->size && NILP (match))
- newentry = XVECTOR (Vsyntax_code_object)->contents[val];
+ return XVECTOR (Vsyntax_code_object)->contents[val];
else
/* Since we can't use a shared object, let's make a new one. */
- newentry = Fcons (make_number (val), match);
-
- SET_RAW_SYNTAX_ENTRY (syntax_table, XINT (c), newentry);
+ return Fcons (make_number (val), match);
+}
+
+/* This comment supplies the doc string for modify-syntax-entry,
+ for make-docfile to see. We cannot put this in the real DEFUN
+ due to limits in the Unix cpp.
+
+DEFUN ("modify-syntax-entry", foo, bar, 2, 3, 0,
+ "Set syntax for character CHAR according to string S.\n\
+The syntax is changed only for table TABLE, which defaults to\n\
+ the current buffer's syntax table.\n\
+The first character of S should be one of the following:\n\
+ Space or - whitespace syntax. w word constituent.\n\
+ _ symbol constituent. . punctuation.\n\
+ ( open-parenthesis. ) close-parenthesis.\n\
+ \" string quote. \\ escape.\n\
+ $ paired delimiter. ' expression quote or prefix operator.\n\
+ < comment starter. > comment ender.\n\
+ / character-quote. @ inherit from `standard-syntax-table'.\n\
+ | generic string fence. ! generic comment fence.\n\
+\n\
+Only single-character comment start and end sequences are represented thus.\n\
+Two-character sequences are represented as described below.\n\
+The second character of S is the matching parenthesis,\n\
+ used only if the first character is `(' or `)'.\n\
+Any additional characters are flags.\n\
+Defined flags are the characters 1, 2, 3, 4, b, p, and n.\n\
+ 1 means CHAR is the start of a two-char comment start sequence.\n\
+ 2 means CHAR is the second character of such a sequence.\n\
+ 3 means CHAR is the start of a two-char comment end sequence.\n\
+ 4 means CHAR is the second character of such a sequence.\n\
+\n\
+There can be up to two orthogonal comment sequences. This is to support\n\
+language modes such as C++. By default, all comment sequences are of style\n\
+a, but you can set the comment sequence style to b (on the second character\n\
+of a comment-start, or the first character of a comment-end sequence) using\n\
+this flag:\n\
+ b means CHAR is part of comment sequence b.\n\
+ n means CHAR is part of a nestable comment sequence.\n\
+\n\
+ p means CHAR is a prefix character for `backward-prefix-chars';\n\
+ such characters are treated as whitespace when they occur\n\
+ between expressions.")
+ (char, s, table)
+*/
+
+DEFUN ("modify-syntax-entry", Fmodify_syntax_entry, Smodify_syntax_entry, 2, 3,
+ /* I really don't know why this is interactive
+ help-form should at least be made useful whilst reading the second arg
+ */
+ "cSet syntax for character: \nsSet syntax for %s to: ",
+ 0 /* See immediately above */)
+ (c, newentry, syntax_table)
+ Lisp_Object c, newentry, syntax_table;
+{
+ CHECK_NUMBER (c, 0);
+
+ if (NILP (syntax_table))
+ syntax_table = current_buffer->syntax_table;
+ else
+ check_syntax_table (syntax_table);
+ SET_RAW_SYNTAX_ENTRY (syntax_table, XINT (c), Fstring_to_syntax (newentry));
return Qnil;
}
\f
Lisp_Object value;
{
register enum syntaxcode code;
- char desc, start1, start2, end1, end2, prefix, comstyle;
+ char desc, start1, start2, end1, end2, prefix, comstyle, comnested;
char str[2];
Lisp_Object first, match_lisp;
end2 = (XINT (first) >> 19) & 1;
prefix = (XINT (first) >> 20) & 1;
comstyle = (XINT (first) >> 21) & 1;
+ comnested = (XINT (first) >> 22) & 1;
if ((int) code < 0 || (int) code >= (int) Smax)
{
insert ("p", 1);
if (comstyle)
insert ("b", 1);
+ if (comnested)
+ insert ("n", 1);
insert_string ("\twhich means: ");
case Sclose:
insert_string ("close"); break;
case Squote:
- insert_string ("quote"); break;
+ insert_string ("prefix"); break;
case Sstring:
insert_string ("string"); break;
case Smath:
insert_string ("comment"); break;
case Sendcomment:
insert_string ("endcomment"); break;
+ case Sinherit:
+ insert_string ("inherit"); break;
+ case Scomment_fence:
+ insert_string ("comment fence"); break;
+ case Sstring_fence:
+ insert_string ("string fence"); break;
default:
insert_string ("invalid");
return;
insert_string (",\n\t is the second character of a comment-end sequence");
if (comstyle)
insert_string (" (comment style b)");
+ if (comnested)
+ insert_string (" (nestable)");
if (prefix)
insert_string (",\n\t is a prefix character for `backward-prefix-chars'");
/* Avoid jumping out of an input field. */
val = XFASTINT (Fconstrain_to_field (make_number (val), make_number (PT),
- Qt, Qnil));
+ Qt, Qnil, Qnil));
SET_PT (val);
return val == orig_val ? Qt : Qnil;
Lisp_Object string, lim;
{
register unsigned int c;
- register int ch;
unsigned char fastmap[0400];
/* If SYNTAXP is 0, STRING may contain multi-byte form of characters
- of which codes don't fit in FASTMAP. In that case, we set the
- first byte of multibyte form (i.e. base leading-code) in FASTMAP
- and set the actual ranges of characters in CHAR_RANGES. In the
- form "X-Y" of STRING, both X and Y must belong to the same
- character set because a range striding across character sets is
- meaningless. */
+ of which codes don't fit in FASTMAP. In that case, set the
+ ranges of characters in CHAR_RANGES. */
int *char_ranges;
int n_char_ranges = 0;
int negate = 0;
int multibyte = !NILP (current_buffer->enable_multibyte_characters);
int string_multibyte;
int size_byte;
+ unsigned char *str;
+ int len;
CHECK_STRING (string, 0);
char_ranges = (int *) alloca (XSTRING (string)->size * (sizeof (int)) * 2);
string_multibyte = STRING_MULTIBYTE (string);
+ str = XSTRING (string)->data;
size_byte = STRING_BYTES (XSTRING (string));
+ /* Adjust the multibyteness of the string to that of the buffer. */
+ if (multibyte != string_multibyte)
+ {
+ int nbytes;
+
+ if (multibyte)
+ nbytes = count_size_as_multibyte (XSTRING (string)->data,
+ XSTRING (string)->size);
+ else
+ nbytes = XSTRING (string)->size;
+ if (nbytes != size_byte)
+ {
+ str = (unsigned char *) alloca (nbytes);
+ copy_text (XSTRING (string)->data, str, size_byte,
+ string_multibyte, multibyte);
+ size_byte = nbytes;
+ }
+ }
+
if (NILP (lim))
XSETINT (lim, forwardp ? ZV : BEGV);
else
bzero (fastmap, sizeof fastmap);
- i = 0, i_byte = 0;
+ i_byte = 0;
if (i_byte < size_byte
&& XSTRING (string)->data[0] == '^')
{
- negate = 1; i++, i_byte++;
+ negate = 1; i_byte++;
}
/* Find the characters specified and set their elements of fastmap.
while (i_byte < size_byte)
{
- int c_leading_code = XSTRING (string)->data[i_byte];
-
- FETCH_STRING_CHAR_ADVANCE (c, string, i, i_byte);
-
- /* Convert multibyteness between what the string has
- and what the buffer has. */
- if (multibyte)
- c = unibyte_char_to_multibyte (c);
- else
- c &= 0377;
+ c = STRING_CHAR_AND_LENGTH (str + i_byte, size_byte - i_byte, len);
+ i_byte += len;
if (syntaxp)
fastmap[syntax_spec_code[c & 0377]] = 1;
if (i_byte == size_byte)
break;
- c_leading_code = XSTRING (string)->data[i_byte];
- FETCH_STRING_CHAR_ADVANCE (c, string, i, i_byte);
+ c = STRING_CHAR_AND_LENGTH (str+i_byte, size_byte-i_byte, len);
+ i_byte += len;
}
if (i_byte < size_byte
- && XSTRING (string)->data[i_byte] == '-')
+ && str[i_byte] == '-')
{
- unsigned int c2, c2_leading_code;
+ unsigned int c2;
/* Skip over the dash. */
- i++, i_byte++;
+ i_byte++;
if (i_byte == size_byte)
break;
/* Get the end of the range. */
- c2_leading_code = XSTRING (string)->data[i_byte];
- FETCH_STRING_CHAR_ADVANCE (c2, string, i, i_byte);
+ c2 =STRING_CHAR_AND_LENGTH (str+i_byte, size_byte-i_byte, len);
+ i_byte += len;
if (SINGLE_BYTE_CHAR_P (c))
{
if (! SINGLE_BYTE_CHAR_P (c2))
- error ("Invalid charcter range: %s",
- XSTRING (string)->data);
+ {
+ /* Handle a range starting with a character of
+ less than 256, and ending with a character of
+ not less than 256. Split that into two
+ ranges, the low one ending at 0377, and the
+ high one starting at the smallest character
+ in the charset of C2 and ending at C2. */
+ int charset = CHAR_CHARSET (c2);
+ int c1 = MAKE_CHAR (charset, 0, 0);
+
+ char_ranges[n_char_ranges++] = c1;
+ char_ranges[n_char_ranges++] = c2;
+ c2 = 0377;
+ }
while (c <= c2)
{
fastmap[c] = 1;
c++;
}
}
- else
+ else if (c <= c2) /* Both C and C2 are multibyte char. */
{
- if (c_leading_code != c2_leading_code)
- error ("Invalid charcter range: %s",
- XSTRING (string)->data);
- fastmap[c_leading_code] = 1;
- if (c <= c2)
- {
- char_ranges[n_char_ranges++] = c;
- char_ranges[n_char_ranges++] = c2;
- }
+ char_ranges[n_char_ranges++] = c;
+ char_ranges[n_char_ranges++] = c2;
}
}
else
{
- fastmap[c_leading_code] = 1;
- if (!SINGLE_BYTE_CHAR_P (c))
+ if (SINGLE_BYTE_CHAR_P (c))
+ fastmap[c] = 1;
+ else
{
char_ranges[n_char_ranges++] = c;
char_ranges[n_char_ranges++] = c;
}
}
- /* If ^ was the first character, complement the fastmap. In
- addition, as all multibyte characters have possibility of
- matching, set all entries for base leading codes, which is
- harmless even if SYNTAXP is 1. */
-
+ /* If ^ was the first character, complement the fastmap. */
if (negate)
for (i = 0; i < sizeof fastmap; i++)
- {
- if (!multibyte || !BASE_LEADING_CODE_P (i))
- fastmap[i] ^= 1;
- else
- fastmap[i] = 1;
- }
+ fastmap[i] ^= 1;
{
int start_point = PT;
if (forwardp)
{
if (multibyte)
- while (pos < XINT (lim) && fastmap[(c = FETCH_BYTE (pos_byte))])
+ while (pos < XINT (lim))
{
- if (!BASE_LEADING_CODE_P (c))
- INC_BOTH (pos, pos_byte);
- else if (n_char_ranges)
+ c = FETCH_MULTIBYTE_CHAR (pos_byte);
+ if (SINGLE_BYTE_CHAR_P (c))
{
- /* We much check CHAR_RANGES for a multibyte
- character. */
- ch = FETCH_MULTIBYTE_CHAR (pos_byte);
- for (i = 0; i < n_char_ranges; i += 2)
- if ((ch >= char_ranges[i] && ch <= char_ranges[i + 1]))
- break;
- if (!(negate ^ (i < n_char_ranges)))
+ if (!fastmap[c])
break;
-
- INC_BOTH (pos, pos_byte);
}
else
{
- if (!negate) break;
- INC_BOTH (pos, pos_byte);
+ /* If we are looking at a multibyte character,
+ we must look up the character in the table
+ CHAR_RANGES. If there's no data in the
+ table, that character is not what we want to
+ skip. */
+
+ /* The following code do the right thing even if
+ n_char_ranges is zero (i.e. no data in
+ CHAR_RANGES). */
+ for (i = 0; i < n_char_ranges; i += 2)
+ if (c >= char_ranges[i] && c <= char_ranges[i + 1])
+ break;
+ if (!(negate ^ (i < n_char_ranges)))
+ break;
}
+ INC_BOTH (pos, pos_byte);
}
else
while (pos < XINT (lim) && fastmap[FETCH_BYTE (pos)])
if (multibyte)
while (pos > XINT (lim))
{
- int savepos = pos_byte;
- DEC_BOTH (pos, pos_byte);
- if (fastmap[(c = FETCH_BYTE (pos_byte))])
+ int prev_pos_byte = pos_byte;
+
+ DEC_POS (prev_pos_byte);
+ c = FETCH_MULTIBYTE_CHAR (prev_pos_byte);
+ if (SINGLE_BYTE_CHAR_P (c))
{
- if (!BASE_LEADING_CODE_P (c))
- ;
- else if (n_char_ranges)
- {
- /* We much check CHAR_RANGES for a multibyte
- character. */
- ch = FETCH_MULTIBYTE_CHAR (pos_byte);
- for (i = 0; i < n_char_ranges; i += 2)
- if (ch >= char_ranges[i] && ch <= char_ranges[i + 1])
- break;
- if (!(negate ^ (i < n_char_ranges)))
- {
- pos++;
- pos_byte = savepos;
- break;
- }
- }
- else
- if (!negate)
- {
- pos++;
- pos_byte = savepos;
- break;
- }
+ if (!fastmap[c])
+ break;
}
else
{
- pos++;
- pos_byte = savepos;
- break;
+ /* See the comment in the previous similar code. */
+ for (i = 0; i < n_char_ranges; i += 2)
+ if (c >= char_ranges[i] && c <= char_ranges[i + 1])
+ break;
+ if (!(negate ^ (i < n_char_ranges)))
+ break;
}
+ pos--;
+ pos_byte = prev_pos_byte;
}
else
while (pos > XINT (lim) && fastmap[FETCH_BYTE (pos - 1)])
code = syntax & 0xff;
if (code == Sendcomment
&& SYNTAX_FLAGS_COMMENT_STYLE (syntax) == style
- && --nesting <= 0)
+ && (SYNTAX_FLAGS_COMMENT_NESTED (syntax) ?
+ (nesting > 0 && --nesting == 0) : nesting < 0))
/* we have encountered a comment end of the same style
as the comment sequence which began this comment
section */
break;
if (nesting > 0
&& code == Scomment
+ && SYNTAX_FLAGS_COMMENT_NESTED (syntax)
&& SYNTAX_FLAGS_COMMENT_STYLE (syntax) == style)
/* we have encountered a nested comment of the same style
as the comment sequence which began this comment section */
if (from < stop && SYNTAX_FLAGS_COMEND_FIRST (syntax)
&& SYNTAX_FLAGS_COMMENT_STYLE (syntax) == style
&& (c1 = FETCH_CHAR (from_byte),
- SYNTAX_COMEND_SECOND (c1)))
+ SYNTAX_COMEND_SECOND (c1))
+ && ((SYNTAX_FLAGS_COMMENT_NESTED (syntax) ||
+ SYNTAX_COMMENT_NESTED (c1)) ? nesting > 0 : nesting < 0))
{
if (--nesting <= 0)
/* we have encountered a comment end of the same style
&& SYNTAX_FLAGS_COMSTART_FIRST (syntax)
&& (c1 = FETCH_CHAR (from_byte),
SYNTAX_COMMENT_STYLE (c1) == style
- && SYNTAX_COMSTART_SECOND (c1)))
+ && SYNTAX_COMSTART_SECOND (c1))
+ && (SYNTAX_FLAGS_COMMENT_NESTED (syntax) ||
+ SYNTAX_COMMENT_NESTED (c1)))
/* we have encountered a nested comment of the same style
as the comment sequence which began this comment
section */
code = SYNTAX (c);
comstart_first = SYNTAX_COMSTART_FIRST (c);
comnested = SYNTAX_COMMENT_NESTED (c);
+ comstyle = SYNTAX_COMMENT_STYLE (c);
INC_BOTH (from, from_byte);
UPDATE_SYNTAX_TABLE_FORWARD (from);
- comstyle = 0;
if (from < stop && comstart_first
&& (c1 = FETCH_CHAR (from_byte),
SYNTAX_COMSTART_SECOND (c1)))
INC_BOTH (from, from_byte);
UPDATE_SYNTAX_TABLE_FORWARD (from);
}
- /* FIXME: here we ignore 2-char endcomments while we don't
- when going backwards. */
}
- while (code == Swhitespace || code == Sendcomment);
+ while (code == Swhitespace || (code == Sendcomment && c == '\n'));
if (code == Scomment_fence)
comstyle = ST_COMMENT_STYLE;
{
while (1)
{
- int quoted, comstart_second;
+ int quoted;
if (from <= stop)
{
DEC_BOTH (from, from_byte);
/* char_quoted does UPDATE_SYNTAX_TABLE_BACKWARD (from). */
quoted = char_quoted (from, from_byte);
- if (quoted)
- {
- DEC_BOTH (from, from_byte);
- goto leave;
- }
c = FETCH_CHAR (from_byte);
code = SYNTAX (c);
comstyle = 0;
comnested = SYNTAX_COMMENT_NESTED (c);
if (code == Sendcomment)
comstyle = SYNTAX_COMMENT_STYLE (c);
- comstart_second = SYNTAX_COMSTART_SECOND (c);
if (from > stop && SYNTAX_COMEND_SECOND (c)
&& prev_char_comend_first (from, from_byte)
&& !char_quoted (from - 1, dec_bytepos (from_byte)))
comstyle = SYNTAX_COMMENT_STYLE (c1);
comnested = comnested || SYNTAX_COMMENT_NESTED (c1);
}
- if (from > stop && comstart_second
- && prev_char_comstart_first (from, from_byte)
- && !char_quoted (from - 1, dec_bytepos (from_byte)))
- {
- code = Scomment;
- DEC_BOTH (from, from_byte);
- }
if (code == Scomment_fence)
{
&out_charpos, &out_bytepos);
if (found == -1)
{
-#if 0 /* cc-mode (and maybe others) relies on the bogus behavior. */
- /* Failure: we should go back to the end of this
- not-quite-endcomment. */
- if (SYNTAX(c) != code)
- /* It was a two-char Sendcomment. */
- INC_BOTH (from, from_byte);
- goto leave;
-#endif
+ if (c == '\n')
+ /* This end-of-line is not an end-of-comment.
+ Treat it like a whitespace.
+ CC-mode (and maybe others) relies on this behavior. */
+ ;
+ else
+ {
+ /* Failure: we should go back to the end of this
+ not-quite-endcomment. */
+ if (SYNTAX(c) != code)
+ /* It was a two-char Sendcomment. */
+ INC_BOTH (from, from_byte);
+ goto leave;
+ }
}
else
- /* We have skipped one comment. */
- from = out_charpos, from_byte = out_bytepos;
- break;
+ {
+ /* We have skipped one comment. */
+ from = out_charpos, from_byte = out_bytepos;
+ break;
+ }
}
- else if (code != Swhitespace && code != Scomment)
+ else if (code != Swhitespace || quoted)
{
leave:
immediate_quit = 0;
}
\f
/* Return syntax code of character C if C is a single byte character
- or `multibyte_symbol_p' is zero. Otherwise, retrun Ssymbol. */
+ or `multibyte_symbol_p' is zero. Otherwise, return Ssymbol. */
#define SYNTAX_WITH_MULTIBYTE_CHECK(c) \
((SINGLE_BYTE_CHAR_P (c) || !multibyte_symbol_p) \
code = SYNTAX_WITH_MULTIBYTE_CHECK (c);
comstart_first = SYNTAX_COMSTART_FIRST (c);
comnested = SYNTAX_COMMENT_NESTED (c);
+ comstyle = SYNTAX_COMMENT_STYLE (c);
prefix = SYNTAX_PREFIX (c);
if (depth == min_depth)
last_good = from;
if (from >= stop) goto lose;
UPDATE_SYNTAX_TABLE_FORWARD (from);
c = FETCH_CHAR (from_byte);
- if (code == Sstring
- ? c == stringterm
+ if (code == Sstring
+ ? (c == stringterm
+ && SYNTAX_WITH_MULTIBYTE_CHECK (c) == Sstring)
: SYNTAX_WITH_MULTIBYTE_CHECK (c) == Sstring_fence)
break;
}
/* Quoting turns anything except a comment-ender
- into a word character. Note that this if cannot be true
+ into a word character. Note that this cannot be true
if we decremented FROM in the if-statement above. */
if (code != Sendcomment && char_quoted (from, from_byte))
code = Sword;
temp_pos--;
UPDATE_SYNTAX_TABLE_BACKWARD (from - 1);
if (!char_quoted (from - 1, temp_pos)
- && stringterm == FETCH_CHAR (temp_pos))
+ && stringterm == (c = FETCH_CHAR (temp_pos))
+ && SYNTAX_WITH_MULTIBYTE_CHECK (c) == Sstring)
break;
DEC_BOTH (from, from_byte);
}
/* curlevel++->last ran into compiler bug on Apollo */
curlevel->last = XINT (Fcar (tem));
if (++curlevel == endlevel)
- error ("Nesting too deep for parser");
+ curlevel--; /* error ("Nesting too deep for parser"); */
curlevel->prev = -1;
curlevel->last = -1;
tem = Fcdr (tem);
if (code == Scomment)
{
+ state.comstyle = SYNTAX_FLAGS_COMMENT_STYLE (prev_from_syntax);
state.incomment = (SYNTAX_FLAGS_COMMENT_NESTED (prev_from_syntax) ?
1 : -1);
state.comstr_start = prev_from;
curlevel->prev = curlevel->last;
break;
- startincomment:
- if (commentstop == 1)
- goto done;
- goto commentloop;
-
case Scomment:
- if (! state.incomment)
- abort ();
if (commentstop || boundary_stop) goto done;
- commentloop:
- /* The (from == BEGV) test is to enter the loop in the middle so
+ startincomment:
+ /* The (from == BEGV) test was to enter the loop in the middle so
that we find a 2-char comment ender even if we start in the
- middle of it. */
+ middle of it. We don't want to do that if we're just at the
+ beginning of the comment (think of (*) ... (*)). */
found = forw_comment (from, from_byte, end,
state.incomment, state.comstyle,
- (from == BEGV) ? 0 : prev_from_syntax,
+ (from == BEGV || from < state.comstr_start + 3)
+ ? 0 : prev_from_syntax,
&out_charpos, &out_bytepos, &state.incomment);
from = out_charpos; from_byte = out_bytepos;
/* Beware! prev_from and friends are invalid now.
Luckily, the `done' doesn't use them and the INC_FROM
sets them to a sane value without looking at them. */
if (!found) goto done;
- INC_FROM;
+ INC_FROM;
state.incomment = 0;
state.comstyle = 0; /* reset the comment style */
if (boundary_stop) goto done;
/* curlevel++->last ran into compiler bug on Apollo */
curlevel->last = prev_from;
if (++curlevel == endlevel)
- error ("Nesting too deep for parser");
+ curlevel--; /* error ("Nesting too deep for parser"); */
curlevel->prev = -1;
curlevel->last = -1;
if (targetdepth == depth) goto done;
else an integer (the current comment nesting).\n\
5. t if following a quote character.\n\
6. the minimum paren-depth encountered during this scan.\n\
- 7. t if in a comment of style b; `syntax-table' if the comment\n\
+ 7. t if in a comment of style b; symbol `syntax-table' if the comment\n\
should be terminated by a generic comment delimiter.\n\
8. character address of start of comment or string; nil if not in one.\n\
9. Intermediate data for continuation of parsing (subject to change).\n\
It is used to initialize the state of the parse. Elements number 1, 2, 6\n\
and 8 are ignored; you can leave off element 8 (the last) entirely.\n\
Sixth arg COMMENTSTOP non-nil means stop at the start of a comment.\n\
- If it is `syntax-table', stop after the start of a comment or a string,\n\
- or after end of a comment or a string.")
+ If it is symbol `syntax-table', stop after the start of a comment or a\n\
+ string, or after end of a comment or a string.")
(from, to, targetdepth, stopbefore, state, commentstop)
*/
Qchar_table_extra_slots = intern ("char-table-extra-slots");
/* Create objects which can be shared among syntax tables. */
- Vsyntax_code_object = Fmake_vector (make_number (13), Qnil);
+ Vsyntax_code_object = Fmake_vector (make_number (Smax), Qnil);
for (i = 0; i < XVECTOR (Vsyntax_code_object)->size; i++)
XVECTOR (Vsyntax_code_object)->contents[i]
= Fcons (make_number (i), Qnil);
"Non-nil means `forward-sexp', etc., should treat comments as whitespace.");
DEFVAR_BOOL ("parse-sexp-lookup-properties", &parse_sexp_lookup_properties,
- "Non-nil means `forward-sexp', etc., grant `syntax-table' property.\n\
-The value of this property should be either a syntax table, or a cons\n\
-of the form (SYNTAXCODE . MATCHCHAR), SYNTAXCODE being the numeric\n\
-syntax code, MATCHCHAR being nil or the character to match (which is\n\
-relevant only for open/close type.");
+ "Non-nil means `forward-sexp', etc., obey `syntax-table' property.\n\
+Otherwise, that text property is simply ignored.\n\
+See the info node `(elisp)Syntax Properties' for a description of the\n\
+`syntax-table' property.");
words_include_escapes = 0;
DEFVAR_BOOL ("words-include-escapes", &words_include_escapes,
defsubr (&Sset_syntax_table);
defsubr (&Schar_syntax);
defsubr (&Smatching_paren);
+ defsubr (&Sstring_to_syntax);
defsubr (&Smodify_syntax_entry);
defsubr (&Sdescribe_syntax);