X-Git-Url: http://git.hcoop.net/bpt/emacs.git/blobdiff_plain/37bef2308fa614efa3b89d9f000cd0272c8955e6..6dd5561c8aaf8485b86fcef163f4c2b2c7e6a3ea:/src/syntax.c diff --git a/src/syntax.c b/src/syntax.c index 81b02a603c..c06cb4bd6e 100644 --- a/src/syntax.c +++ b/src/syntax.c @@ -1,5 +1,5 @@ /* GNU Emacs routines to deal with syntax tables; also word and list parsing. - Copyright (C) 1985, 1987, 1992 Free Software Foundation, Inc. + Copyright (C) 1985, 1987, 1993 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -18,7 +18,7 @@ along with GNU Emacs; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "config.h" +#include #include #include "lisp.h" #include "commands.h" @@ -27,6 +27,9 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ Lisp_Object Qsyntax_table_p; +static void scan_sexps_forward (); +static int char_quoted (); + int words_include_escapes; /* This is the internal form of the parse state used in parse-partial-sexp. */ @@ -81,10 +84,7 @@ find_defun_start (pos) return find_start_value; /* Back up to start of line. */ - tem = scan_buffer ('\n', pos, -1, &shortage); - /* If we found a newline, we moved back over it, so advance fwd past it. */ - if (shortage == 0) - tem++; + tem = scan_buffer ('\n', pos, -1, &shortage, 1); while (tem > BEGV) { @@ -92,9 +92,7 @@ find_defun_start (pos) if (SYNTAX (FETCH_CHAR (tem)) == Sopen) break; /* Move to beg of previous line. */ - tem = scan_buffer ('\n', tem, -2, &shortage); - if (shortage == 0) - tem++; + tem = scan_buffer ('\n', tem, -2, &shortage, 1); } /* Record what we found, for the next try. */ @@ -125,7 +123,7 @@ check_syntax_table (obj) register Lisp_Object tem; while (tem = Fsyntax_table_p (obj), NILP (tem)) - obj = wrong_type_argument (Qsyntax_table_p, obj, 0); + obj = wrong_type_argument (Qsyntax_table_p, obj); return obj; } @@ -178,7 +176,8 @@ One argument, a syntax table.") table = check_syntax_table (table); current_buffer->syntax_table = table; /* Indicate that this buffer now has a specified syntax table. */ - current_buffer->local_var_flags |= buffer_local_flags.syntax_table; + current_buffer->local_var_flags + |= XFASTINT (buffer_local_flags.syntax_table); return table; } @@ -198,7 +197,7 @@ unsigned char syntax_spec_code[0400] = 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, (char) Scomment, 0377, (char) Sendcomment, 0377, - 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, /* @, A, ... */ + (char) Sinherit, 0377, 0377, 0377, 0377, 0377, 0377, 0377, /* @, A ... */ 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, (char) Sword, 0377, 0377, 0377, 0377, (char) Sescape, 0377, 0377, (char) Ssymbol, @@ -210,9 +209,9 @@ unsigned char syntax_spec_code[0400] = /* Indexed by syntax code, give the letter that describes it. */ -char syntax_code_spec[13] = +char syntax_code_spec[14] = { - ' ', '.', 'w', '_', '(', ')', '\'', '\"', '$', '\\', '/', '<', '>' + ' ', '.', 'w', '_', '(', ')', '\'', '\"', '$', '\\', '/', '<', '>', '@' }; DEFUN ("char-syntax", Fchar_syntax, Schar_syntax, 1, 1, 0, @@ -231,7 +230,7 @@ are listed in the documentation of `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, 0, 0, 0, +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\ @@ -241,8 +240,9 @@ The first character of S should be one of the following:\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.\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\ @@ -256,15 +256,15 @@ Defined flags are the characters 1, 2, 3, 4, b, and p.\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 of a\n\ -comment-start, or the first character of a comment-end sequence) by using\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 C is part of comment sequence b.\n\ \n\ p means C 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, @@ -332,6 +332,7 @@ DEFUN ("modify-syntax-entry", Fmodify_syntax_entry, Smodify_syntax_entry, 2, 3, /* Dump syntax table to buffer in human-readable format */ +static void describe_syntax (value) Lisp_Object value; { @@ -419,6 +420,8 @@ describe_syntax (value) insert_string ("comment"); break; case Sendcomment: insert_string ("endcomment"); break; + case Sinherit: + insert_string ("inherit"); break; default: insert_string ("invalid"); return; @@ -427,9 +430,7 @@ describe_syntax (value) if (match) { insert_string (", matches "); - - str[0] = match, str[1] = 0; - insert (str, 1); + insert_char (match); } if (start1) @@ -450,13 +451,13 @@ describe_syntax (value) insert_string ("\n"); } -Lisp_Object +static Lisp_Object describe_syntax_1 (vector) Lisp_Object vector; { struct buffer *old = current_buffer; set_buffer_internal (XBUFFER (Vstandard_output)); - describe_vector (vector, Qnil, describe_syntax, 0, Qnil, Qnil); + describe_vector (vector, Qnil, describe_syntax, 0, Qnil); set_buffer_internal (old); return Qnil; } @@ -570,6 +571,278 @@ and nil is returned.") return Qt; } +DEFUN ("forward-comment", Fforward_comment, Sforward_comment, 1, 1, 0, + "Move forward across up to N comments. If N is negative, move backward.\n\ +Stop scanning if we find something other than a comment or whitespace.\n\ +Set point to where scanning stops.\n\ +If N comments are found as expected, with nothing except whitespace\n\ +between them, return t; otherwise return nil.") + (count) + Lisp_Object count; +{ + register int from; + register int stop; + register int c; + register enum syntaxcode code; + int comstyle = 0; /* style of comment encountered */ + int found; + int count1; + + CHECK_NUMBER (count, 0); + count1 = XINT (count); + + immediate_quit = 1; + QUIT; + + from = PT; + + while (count1 > 0) + { + stop = ZV; + do + { + if (from == stop) + { + SET_PT (from); + return Qnil; + } + c = FETCH_CHAR (from); + code = SYNTAX (c); + from++; + comstyle = 0; + if (from < stop && SYNTAX_COMSTART_FIRST (c) + && SYNTAX_COMSTART_SECOND (FETCH_CHAR (from))) + { + /* We have encountered a comment start sequence and we + are ignoring all text inside comments. We must record + the comment style this sequence begins so that later, + only a comment end of the same style actually ends + the comment section. */ + code = Scomment; + comstyle = SYNTAX_COMMENT_STYLE (FETCH_CHAR (from)); + from++; + } + } + while (code == Swhitespace || code == Sendcomment); + if (code != Scomment) + { + immediate_quit = 0; + SET_PT (from - 1); + return Qnil; + } + /* We're at the start of a comment. */ + while (1) + { + if (from == stop) + { + immediate_quit = 0; + SET_PT (from); + return Qnil; + } + c = FETCH_CHAR (from); + if (SYNTAX (c) == Sendcomment + && SYNTAX_COMMENT_STYLE (c) == comstyle) + /* we have encountered a comment end of the same style + as the comment sequence which began this comment + section */ + break; + from++; + if (from < stop && SYNTAX_COMEND_FIRST (c) + && SYNTAX_COMEND_SECOND (FETCH_CHAR (from)) + && SYNTAX_COMMENT_STYLE (c) == comstyle) + /* we have encountered a comment end of the same style + as the comment sequence which began this comment + section */ + { from++; break; } + } + /* We have skipped one comment. */ + count1--; + } + + while (count1 < 0) + { + stop = BEGV; + while (from > stop) + { + int quoted; + + from--; + quoted = char_quoted (from); + if (quoted) + from--; + c = FETCH_CHAR (from); + code = SYNTAX (c); + comstyle = 0; + if (code == Sendcomment) + comstyle = SYNTAX_COMMENT_STYLE (c); + if (from > stop && SYNTAX_COMEND_SECOND (c) + && SYNTAX_COMEND_FIRST (FETCH_CHAR (from - 1)) + && !char_quoted (from - 1)) + { + /* We must record the comment style encountered so that + later, we can match only the proper comment begin + sequence of the same style. */ + code = Sendcomment; + comstyle = SYNTAX_COMMENT_STYLE (FETCH_CHAR (from - 1)); + from--; + } + + if (code == Sendcomment && !quoted) + { +#if 0 + if (code != SYNTAX (c)) + /* For a two-char comment ender, we can assume + it does end a comment. So scan back in a simple way. */ + { + if (from != stop) from--; + while (1) + { + if (SYNTAX (c = FETCH_CHAR (from)) == Scomment + && SYNTAX_COMMENT_STYLE (c) == comstyle) + break; + if (from == stop) + { + immediate_quit = 0; + SET_PT (from); + return Qnil; + } + from--; + if (SYNTAX_COMSTART_SECOND (c) + && SYNTAX_COMSTART_FIRST (FETCH_CHAR (from)) + && SYNTAX_COMMENT_STYLE (c) == comstyle + && !char_quoted (from)) + break; + } + break; + } +#endif /* 0 */ + + /* Look back, counting the parity of string-quotes, + and recording the comment-starters seen. + When we reach a safe place, assume that's not in a string; + then step the main scan to the earliest comment-starter seen + an even number of string quotes away from the safe place. + + 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; + char my_stringend = 0; + int string_lossage = 0; + int comment_end = from; + int comstart_pos = 0; + int comstart_parity = 0; + + /* At beginning of range to scan, we're outside of strings; + that determines quote parity to the comment-end. */ + while (from != stop) + { + /* Move back and examine a character. */ + from--; + + c = FETCH_CHAR (from); + code = SYNTAX (c); + + /* If this char is the second of a 2-char comment sequence, + back up and give the pair the appropriate syntax. */ + if (from > stop && SYNTAX_COMEND_SECOND (c) + && SYNTAX_COMEND_FIRST (FETCH_CHAR (from - 1))) + { + code = Sendcomment; + from--; + } + + else if (from > stop && SYNTAX_COMSTART_SECOND (c) + && SYNTAX_COMSTART_FIRST (FETCH_CHAR (from - 1)) + && comstyle == SYNTAX_COMMENT_STYLE (c)) + { + code = Scomment; + from--; + } + + /* Ignore escaped characters. */ + if (char_quoted (from)) + 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; + } + + /* Record comment-starters according to that + quote-parity to the comment-end. */ + if (code == Scomment) + { + comstart_parity = parity; + comstart_pos = from; + } + + /* 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)) == comstyle) + break; + + /* Assume a defun-start point is outside of strings. */ + if (code == Sopen + && (from == stop || FETCH_CHAR (from - 1) == '\n')) + break; + } + + if (comstart_pos == 0) + from = comment_end; + /* 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 (comstart_parity == 0 && !string_lossage) + from = comstart_pos; + else + { + /* We had two kinds of string delimiters mixed up + together. Decode this going forwards. + Scan fwd from the previous comment ender + to the one in question; this records where we + last passed a comment starter. */ + struct lisp_parse_state state; + scan_sexps_forward (&state, find_defun_start (comment_end), + comment_end - 1, -10000, 0, Qnil, 0); + if (state.incomment) + from = state.comstart; + else + /* We can't grok this as a comment; scan it normally. */ + from = comment_end; + } + } + /* We have skipped one comment. */ + break; + } + else if ((code != Swhitespace && code != Scomment) || quoted) + { + immediate_quit = 0; + SET_PT (from + 1); + return Qnil; + } + } + + count1++; + } + + SET_PT (from); + immediate_quit = 0; + return Qt; +} + int parse_sexp_ignore_comments; Lisp_Object @@ -747,6 +1020,9 @@ scan_lists (from, count, depth, sexpflag) from--; c = FETCH_CHAR (from); code = SYNTAX (c); + comstyle = 0; + if (code == Sendcomment) + comstyle = SYNTAX_COMMENT_STYLE (c); if (from > stop && SYNTAX_COMEND_SECOND (c) && SYNTAX_COMEND_FIRST (FETCH_CHAR (from - 1)) && !char_quoted (from - 1) @@ -812,6 +1088,7 @@ scan_lists (from, count, depth, sexpflag) case Sendcomment: if (!parse_sexp_ignore_comments) break; +#if 0 if (code != SYNTAX (c)) /* For a two-char comment ender, we can assume it does end a comment. So scan back in a simple way. */ @@ -832,6 +1109,7 @@ scan_lists (from, count, depth, sexpflag) } break; } +#endif /* 0 */ /* Look back, counting the parity of string-quotes, and recording the comment-starters seen. @@ -902,7 +1180,7 @@ scan_lists (from, count, depth, sexpflag) } /* If we find another earlier comment-ender, - any comment-starts earier than that don't count + 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)) == comstyle) @@ -932,7 +1210,7 @@ scan_lists (from, count, depth, sexpflag) last passed a comment starter. */ struct lisp_parse_state state; scan_sexps_forward (&state, find_defun_start (comment_end), - comment_end - 1, -10000, 0, Qnil); + comment_end - 1, -10000, 0, Qnil, 0); if (state.incomment) from = state.comstart; else @@ -978,6 +1256,7 @@ scan_lists (from, count, depth, sexpflag) /* NOTREACHED */ } +static int char_quoted (pos) register int pos; { @@ -1058,13 +1337,17 @@ This includes chars with \"quote\" or \"prefix\" syntax (' or p).") /* Parse forward from FROM to END, assuming that FROM has state OLDSTATE (nil means FROM is start of function), and return a description of the state of the parse at END. - If STOPBEFORE is nonzero, stop at the start of an atom. */ + If STOPBEFORE is nonzero, stop at the start of an atom. + If COMMENTSTOP is nonzero, stop at the start of a comment. */ -scan_sexps_forward (stateptr, from, end, targetdepth, stopbefore, oldstate) +static void +scan_sexps_forward (stateptr, from, end, targetdepth, + stopbefore, oldstate, commentstop) struct lisp_parse_state *stateptr; register int from; int end, targetdepth, stopbefore; Lisp_Object oldstate; + int commentstop; { struct lisp_parse_state state; @@ -1117,7 +1400,6 @@ scan_sexps_forward (stateptr, from, end, targetdepth, stopbefore, oldstate) style a. if it is non-nil, we are in comment style b */ oldstate = Fcdr (oldstate); oldstate = Fcdr (oldstate); - oldstate = Fcdr (oldstate); tem = Fcar (oldstate); state.comstyle = !NILP (tem); } @@ -1141,14 +1423,18 @@ scan_sexps_forward (stateptr, from, end, targetdepth, stopbefore, oldstate) { code = SYNTAX (FETCH_CHAR (from)); from++; - if (from < end && SYNTAX_COMSTART_FIRST (FETCH_CHAR (from - 1)) - && SYNTAX_COMSTART_SECOND (FETCH_CHAR (from))) + if (code == Scomment) + state.comstart = from-1; + + else if (from < end && SYNTAX_COMSTART_FIRST (FETCH_CHAR (from - 1)) + && SYNTAX_COMSTART_SECOND (FETCH_CHAR (from))) { /* Record the comment style we have entered so that only the comment-end sequence of the same style actually terminates the comment section. */ code = Scomment; state.comstyle = SYNTAX_COMMENT_STYLE (FETCH_CHAR (from)); + state.comstart = from-1; from++; } @@ -1202,8 +1488,9 @@ scan_sexps_forward (stateptr, from, end, targetdepth, stopbefore, oldstate) case Scomment: state.incomment = 1; - state.comstart = from; startincomment: + if (commentstop) + goto done; while (1) { if (from == end) goto done; @@ -1305,36 +1592,37 @@ scan_sexps_forward (stateptr, from, end, targetdepth, stopbefore, oldstate) for make-docfile to see. We cannot put this in the real DEFUN due to limits in the Unix cpp. -DEFUN ("parse-partial-sexp", Ffoo, Sfoo, 2, 5, 0, +DEFUN ("parse-partial-sexp", Ffoo, Sfoo, 2, 6, 0, "Parse Lisp syntax starting at FROM until TO; return status of parse at TO.\n\ Parsing stops at TO or when certain criteria are met;\n\ point is set to where parsing stops.\n\ If fifth arg STATE is omitted or nil,\n\ parsing assumes that FROM is the beginning of a function.\n\ Value is a list of eight elements describing final state of parsing:\n\ - 1. depth in parens.\n\ - 2. character address of start of innermost containing list; nil if none.\n\ - 3. character address of start of last complete sexp terminated.\n\ - 4. non-nil if inside a string.\n\ + 0. depth in parens.\n\ + 1. character address of start of innermost containing list; nil if none.\n\ + 2. character address of start of last complete sexp terminated.\n\ + 3. non-nil if inside a string.\n\ (it is the character that will terminate the string.)\n\ - 5. t if inside a comment.\n\ - 6. t if following a quote character.\n\ - 7. the minimum paren-depth encountered during this scan.\n\ - 8. t if in a comment of style `b'.\n\ + 4. t if inside a comment.\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'.\n\ If third arg TARGETDEPTH is non-nil, parsing stops if the depth\n\ in parentheses becomes equal to TARGETDEPTH.\n\ Fourth arg STOPBEFORE non-nil means stop when come to\n\ any character that starts a sexp.\n\ -Fifth arg STATE is a seven-list like what this function returns.\n\ +Fifth arg STATE is an eight-list like what this function returns.\n\ It is used to initialize the state of the parse. Its second and third -elements are ignored.") - (from, to, targetdepth, stopbefore, state) +elements are ignored. +Sixth args COMMENTSTOP non-nil means stop at the start of a comment.") + (from, to, targetdepth, stopbefore, state, commentstop) */ -DEFUN ("parse-partial-sexp", Fparse_partial_sexp, Sparse_partial_sexp, 2, 5, 0, +DEFUN ("parse-partial-sexp", Fparse_partial_sexp, Sparse_partial_sexp, 2, 6, 0, 0 /* See immediately above */) - (from, to, targetdepth, stopbefore, oldstate) - Lisp_Object from, to, targetdepth, stopbefore, oldstate; + (from, to, targetdepth, stopbefore, oldstate, commentstop) + Lisp_Object from, to, targetdepth, stopbefore, oldstate, commentstop; { struct lisp_parse_state state; int target; @@ -1349,7 +1637,8 @@ DEFUN ("parse-partial-sexp", Fparse_partial_sexp, Sparse_partial_sexp, 2, 5, 0, validate_region (&from, &to); scan_sexps_forward (&state, XINT (from), XINT (to), - target, !NILP (stopbefore), oldstate); + target, !NILP (stopbefore), oldstate, + !NILP (commentstop)); SET_PT (state.location); @@ -1425,6 +1714,7 @@ syms_of_syntax () defsubr (&Sforward_word); + defsubr (&Sforward_comment); defsubr (&Sscan_lists); defsubr (&Sscan_sexps); defsubr (&Sbackward_prefix_chars);