📄 syntax.c
字号:
/* GNU Emacs routines to deal with syntax tables; also word and list parsing. Copyright (C) 1985, 1987, 1990 Free Software Foundation, Inc.This file is part of GNU Emacs.GNU Emacs is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 1, or (at your option)any later version.GNU Emacs is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with GNU Emacs; see the file COPYING. If not, write tothe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */#include "config.h"#include <ctype.h>#include "lisp.h"#include "commands.h"#include "buffer.h"#include "syntax.h"Lisp_Object Qsyntax_table_p;DEFUN ("syntax-table-p", Fsyntax_table_p, Ssyntax_table_p, 1, 1, 0, "Return t if ARG is a syntax table.\n\Any vector of 256 elements will do.") (obj) Lisp_Object obj;{ if (XTYPE (obj) == Lisp_Vector && XVECTOR (obj)->size == 0400) return Qt; return Qnil;}Lisp_Objectcheck_syntax_table (obj) Lisp_Object obj;{ register Lisp_Object tem; while (tem = Fsyntax_table_p (obj), NULL (tem)) obj = wrong_type_argument (Qsyntax_table_p, obj, 0); return obj;} DEFUN ("syntax-table", Fsyntax_table, Ssyntax_table, 0, 0, 0, "Return the current syntax table.\n\This is the one specified by the current buffer.") (){ return current_buffer->syntax_table;}DEFUN ("standard-syntax-table", Fstandard_syntax_table, Sstandard_syntax_table, 0, 0, 0, "Return the standard syntax table.\n\This is the one used for new buffers.") (){ return Vstandard_syntax_table;}DEFUN ("copy-syntax-table", Fcopy_syntax_table, Scopy_syntax_table, 0, 1, 0, "Construct a new syntax table and return it.\n\It is a copy of the TABLE, which defaults to the standard syntax table.") (table) Lisp_Object table;{ Lisp_Object size, val; XFASTINT (size) = 0400; XFASTINT (val) = 0; val = Fmake_vector (size, val); if (!NULL (table)) table = check_syntax_table (table); else if (NULL (Vstandard_syntax_table)) /* Can only be null during initialization */ return val; else table = Vstandard_syntax_table; bcopy (XVECTOR (table)->contents, XVECTOR (val)->contents, 0400 * sizeof (Lisp_Object)); return val;}DEFUN ("set-syntax-table", Fset_syntax_table, Sset_syntax_table, 1, 1, 0, "Select a new syntax table for the current buffer.\n\One argument, a syntax table.") (table) Lisp_Object 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; return table;}/* Convert a letter which signifies a syntax code into the code it signifies. This is used by modify-syntax-entry, and other things. */char syntax_spec_code[0400] = { 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, (char) Swhitespace, 0377, (char) Sstring, 0377, (char) Smath, 0377, 0377, (char) Squote, (char) Sopen, (char) Sclose, 0377, 0377, 0377, (char) Swhitespace, (char) Spunct, (char) Scharquote, 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, ... */ 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, 0377, 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, 0377, 0377, 0377, 0377 };/* Indexed by syntax code, give the letter that describes it. */char syntax_code_spec[13] = { ' ', '.', 'w', '_', '(', ')', '\'', '\"', '$', '\\', '/', '<', '>' };DEFUN ("char-syntax", Fchar_syntax, Schar_syntax, 1, 1, 0, "Return the syntax code of CHAR, described by a character.\n\For example, if CHAR is a word constituent, ?w is returned.\n\The characters that correspond to various syntax codes\n\are listed in the documentation of modify-syntax-entry.") (ch) Lisp_Object ch;{ CHECK_NUMBER (ch, 0); return make_number (syntax_code_spec[(int) SYNTAX (0xFF & XINT (ch))]);}/* 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, 0, 0, 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 whitespace syntax. w word constituent.\n\ _ symbol constituent. . punctuation.\n\ ( open-parenthesis. ) close-parenthesis.\n\ \" string quote. \\ character-quote.\n\ $ paired delimiter. ' expression prefix operator.\n\ < comment starter. > comment ender.\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 and 4.\n\ 1 means C is the start of a two-char comment start sequence.\n\ 2 means C is the second character of such a sequence.\n\ 3 means C is the start of a two-char comment end sequence.\n\ 4 means C is the second character of such a sequence.")*/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;{ register unsigned char *p, match; register enum syntaxcode code; Lisp_Object val; CHECK_NUMBER (c, 0); CHECK_STRING (newentry, 1); if (NULL (syntax_table)) syntax_table = current_buffer->syntax_table; else syntax_table = check_syntax_table (syntax_table); p = XSTRING (newentry)->data; code = (enum syntaxcode) syntax_spec_code[*p++]; if (((int) code & 0377) == 0377) error ("invalid syntax description letter: %c", c); match = *p; if (match) p++; if (match == ' ') match = 0; XFASTINT (val) = (match << 8) + (int) code; while (*p) switch (*p++) { case '1': XFASTINT (val) |= 1 << 16; break; case '2': XFASTINT (val) |= 1 << 17; break; case '3': XFASTINT (val) |= 1 << 18; break; case '4': XFASTINT (val) |= 1 << 19; break; } XVECTOR (syntax_table)->contents[0xFF & XINT (c)] = val; return Qnil;}/* Dump syntax table to buffer in human-readable format */describe_syntax (value) Lisp_Object value;{ register enum syntaxcode code; char desc, match, start1, start2, end1, end2; char str[2]; Findent_to (make_number (16), make_number (1)); if (XTYPE (value) != Lisp_Int) { InsStr ("invalid"); return; } code = (enum syntaxcode) (XINT (value) & 0377); match = (XINT (value) >> 8) & 0377; start1 = (XINT (value) >> 16) & 1; start2 = (XINT (value) >> 17) & 1; end1 = (XINT (value) >> 18) & 1; end2 = (XINT (value) >> 19) & 1; if ((int) code < 0 || (int) code >= (int) Smax) { InsStr ("invalid"); return; } desc = syntax_code_spec[(int) code]; str[0] = desc, str[1] = 0; insert (str, 1); str[0] = match ? match : ' '; insert (str, 1); if (start1) insert ("1", 1); if (start2) insert ("2", 1); if (end1) insert ("3", 1); if (end2) insert ("4", 1); InsStr ("\twhich means: ");#ifdef SWITCH_ENUM_BUG switch ((int) code)#else switch (code)#endif { case Swhitespace: InsStr ("whitespace"); break; case Spunct: InsStr ("punctuation"); break; case Sword: InsStr ("word"); break; case Ssymbol: InsStr ("symbol"); break; case Sopen: InsStr ("open"); break; case Sclose: InsStr ("close"); break; case Squote: InsStr ("quote"); break; case Sstring: InsStr ("string"); break; case Smath: InsStr ("math"); break; case Sescape: InsStr ("escape"); break; case Scharquote: InsStr ("charquote"); break; case Scomment: InsStr ("comment"); break; case Sendcomment: InsStr ("endcomment"); break; default: InsStr ("invalid"); return; } if (match) { InsStr (", matches "); str[0] = match, str[1] = 0; insert (str, 1); } if (start1) InsStr (",\n\t is the first character of a comment-start sequence"); if (start2) InsStr (",\n\t is the second character of a comment-start sequence"); if (end1) InsStr (",\n\t is the first character of a comment-end sequence"); if (end2) InsStr (",\n\t is the second character of a comment-end sequence"); InsStr ("\n");}Lisp_Objectdescribe_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); set_buffer_internal (old); return Qnil;}DEFUN ("describe-syntax", Fdescribe_syntax, Sdescribe_syntax, 0, 0, "", "Describe the syntax specifications in the syntax table.\n\The descriptions are inserted in a buffer, which is selected so you can see it.") (){ internal_with_output_to_temp_buffer ("*Help*", describe_syntax_1, current_buffer->syntax_table); return Qnil;}/* Return the position across `count' words from `from'. If that many words cannot be found before the end of the buffer, return 0. `count' negative means scan backward and stop at word beginning. */scan_words (from, count) register int from, count;{ register int beg = BEGV; register int end = ZV; immediate_quit = 1; QUIT; while (count > 0) { while (1) { if (from == end) { immediate_quit = 0; return 0; } if (SYNTAX(FETCH_CHAR (from)) == Sword) break; from++; } while (1) { if (from == end) break; if (SYNTAX(FETCH_CHAR (from)) != Sword) break; from++; } count--; } while (count < 0) { while (1) { if (from == beg) { immediate_quit = 0; return 0; } if (SYNTAX(FETCH_CHAR (from - 1)) == Sword) break; from--; } while (1) { if (from == beg) break; if (SYNTAX(FETCH_CHAR (from - 1)) != Sword) break; from--; } count++; } immediate_quit = 0; return from;}DEFUN ("forward-word", Fforward_word, Sforward_word, 1, 1, "p", "Move point forward ARG words (backward if ARG is negative).\n\Normally returns t.\n\If an edge of the buffer is reached, point is left there\n\and nil is returned.") (count) Lisp_Object count;{ int val; CHECK_NUMBER (count, 0); if (!(val = scan_words (point, XINT (count)))) { SET_PT (XINT (count) > 0 ? ZV : BEGV); return Qnil; } SET_PT (val); return Qt;}int parse_sexp_ignore_comments;Lisp_Objectscan_lists (from, count, depth, sexpflag) register int from; int count, depth, sexpflag;{ Lisp_Object val; register int stop; register int c; char stringterm; int quoted; int mathexit = 0; register enum syntaxcode code; int min_depth = depth; /* Err out if depth gets less than this. */ if (depth > 0) min_depth = 0; immediate_quit = 1; QUIT; while (count > 0) { stop = ZV; while (from < stop) { c = FETCH_CHAR (from); code = SYNTAX(c); from++; if (from < stop && SYNTAX_COMSTART_FIRST (c) && SYNTAX_COMSTART_SECOND (FETCH_CHAR (from)) && parse_sexp_ignore_comments) code = Scomment, from++;#ifdef SWITCH_ENUM_BUG switch ((int) code)#else switch (code)#endif { case Sescape: case Scharquote: if (from == stop) goto lose; from++; /* treat following character as a word constituent */ case Sword: case Ssymbol: if (depth || !sexpflag) break; /* This word counts as a sexp; return at end of it. */ while (from < stop) {#ifdef SWITCH_ENUM_BUG switch ((int) SYNTAX(FETCH_CHAR (from)))#else switch (SYNTAX(FETCH_CHAR (from)))#endif { case Scharquote: case Sescape: from++; if (from == stop) goto lose; break; case Sword: case Ssymbol: case Squote: break; default: goto done; } from++; } goto done; case Scomment: if (!parse_sexp_ignore_comments) break; while (1) { if (from == stop) goto done; if (SYNTAX (c = FETCH_CHAR (from)) == Sendcomment) break; from++; if (from < stop && SYNTAX_COMEND_FIRST (c) && SYNTAX_COMEND_SECOND (FETCH_CHAR (from))) { from++; break; } } break; case Smath: if (!sexpflag) break; if (from != stop && c == FETCH_CHAR (from)) from++; if (mathexit) { mathexit = 0; goto close1; } mathexit = 1; case Sopen: if (!++depth) goto done; break; case Sclose: close1: if (!--depth) goto done; if (depth < min_depth) error ("Containing expression ends prematurely"); break; case Sstring: stringterm = FETCH_CHAR (from - 1); while (1) { if (from >= stop) goto lose; if (FETCH_CHAR (from) == stringterm) break;#ifdef SWITCH_ENUM_BUG switch ((int) SYNTAX(FETCH_CHAR (from)))#else switch (SYNTAX(FETCH_CHAR (from)))#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -