X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/9690d0263a5d95ddfff437dcef032db829e0a88f..660872b63b75b61d11b09471b5a254e1e5db3c1c:/src/syntax.c diff --git a/src/syntax.c b/src/syntax.c index 1b3f9fc9dc..695b519c5f 100644 --- a/src/syntax.c +++ b/src/syntax.c @@ -162,7 +162,7 @@ update_syntax_table (charpos, count, init, object) } 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"); @@ -172,21 +172,21 @@ update_syntax_table (charpos, count, init, object) error ("Error in syntax_table logic for intervals <-"); /* Update the interval. */ i = update_interval (i, charpos); - if (oldi->position != INTERVAL_LAST_POS (i)) + if (!gl_state.left_ok || oldi->position != INTERVAL_LAST_POS (i)) { 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 (!gl_state.right_ok || i->position != INTERVAL_LAST_POS (oldi)) { invalidate = 0; gl_state.left_ok = 1; /* Invalidate the other end. */ @@ -206,9 +206,9 @@ update_syntax_table (charpos, count, init, object) 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; @@ -425,19 +425,19 @@ prev_char_comend_first (pos, pos_byte) /* 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. @@ -479,7 +479,6 @@ back_comment (from, from_byte, stop, comnested, comstyle, charpos_ptr, bytepos_p int comment_end_byte = from_byte; int comstart_pos = 0; int comstart_byte; - int scanstart = from - 1; /* Place where the containing defun starts, or 0 if we didn't come across it yet. */ int defun_start = 0; @@ -487,44 +486,82 @@ back_comment (from, from_byte, stop, comnested, comstyle, charpos_ptr, bytepos_p 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)) - { - 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)) + /* 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)) { - 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. */ @@ -573,7 +610,9 @@ back_comment (from, from_byte, stop, comnested, comstyle, charpos_ptr, bytepos_p break; case Sendcomment: - if (SYNTAX_COMMENT_STYLE (FETCH_CHAR (from_byte)) == comstyle) + 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) @@ -855,86 +894,35 @@ DEFUN ("matching-paren", Fmatching_paren, Smatching_paren, 1, 1, 0, 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; @@ -977,13 +965,72 @@ DEFUN ("modify-syntax-entry", Fmodify_syntax_entry, Smodify_syntax_entry, 2, 3, } 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; } @@ -1085,7 +1132,7 @@ describe_syntax (value) case Sclose: insert_string ("close"); break; case Squote: - insert_string ("quote"); break; + insert_string ("prefix"); break; case Sstring: insert_string ("string"); break; case Smath: @@ -1098,6 +1145,12 @@ describe_syntax (value) 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; @@ -1343,7 +1396,6 @@ skip_chars (forwardp, syntaxp, string, lim) 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, set the @@ -1444,17 +1496,18 @@ skip_chars (forwardp, syntaxp, string, lim) { if (! SINGLE_BYTE_CHAR_P (c2)) { - /* Handle a range such as \177-\377 in multibyte - mode. Split that into two ranges, the low - one ending at 0237, and the high one starting - at the smallest character in the charset of - C2 and ending at C2. */ + /* 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 = 0237; + c2 = 0377; } while (c <= c2) { @@ -1696,7 +1749,8 @@ forw_comment (from, from_byte, stop, nesting, style, prev_syntax, 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 */ @@ -1709,6 +1763,7 @@ forw_comment (from, from_byte, stop, nesting, style, prev_syntax, 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 */ @@ -1720,7 +1775,9 @@ forw_comment (from, from_byte, stop, nesting, style, prev_syntax, 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 @@ -1738,7 +1795,9 @@ forw_comment (from, from_byte, stop, nesting, style, prev_syntax, && 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 */ @@ -1819,10 +1878,8 @@ between them, return t; otherwise return nil.") 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; @@ -1853,7 +1910,7 @@ between them, return t; otherwise return nil.") { while (1) { - int quoted, comstart_second; + int quoted; if (from <= stop) { @@ -1876,7 +1933,6 @@ between them, return t; otherwise return nil.") 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))) @@ -1892,13 +1948,6 @@ between them, return t; otherwise return nil.") 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) { @@ -1932,21 +1981,29 @@ between them, return t; otherwise return nil.") &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) { leave: immediate_quit = 0; @@ -1965,7 +2022,7 @@ between them, return t; otherwise return nil.") } /* 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) \ @@ -2134,8 +2191,9 @@ scan_lists (from, count, depth, sexpflag) 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; @@ -2312,7 +2370,8 @@ scan_lists (from, count, depth, sexpflag) 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); } @@ -2885,7 +2944,7 @@ init_syntax_once () 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); @@ -2991,6 +3050,7 @@ relevant only for open/close type."); defsubr (&Sset_syntax_table); defsubr (&Schar_syntax); defsubr (&Smatching_paren); + defsubr (&Sstring_to_syntax); defsubr (&Smodify_syntax_entry); defsubr (&Sdescribe_syntax);