|
|
1.1 root 1: /* GNU Emacs routines to deal with syntax tables; also word and list parsing.
2: Copyright (C) 1985, 1987, 1990 Free Software Foundation, Inc.
3:
4: This file is part of GNU Emacs.
5:
6: GNU Emacs is free software; you can redistribute it and/or modify
7: it under the terms of the GNU General Public License as published by
8: the Free Software Foundation; either version 1, or (at your option)
9: any later version.
10:
11: GNU Emacs is distributed in the hope that it will be useful,
12: but WITHOUT ANY WARRANTY; without even the implied warranty of
13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14: GNU General Public License for more details.
15:
16: You should have received a copy of the GNU General Public License
17: along with GNU Emacs; see the file COPYING. If not, write to
18: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19:
20:
21: #include "config.h"
22: #include <ctype.h>
23: #include "lisp.h"
24: #include "commands.h"
25: #include "buffer.h"
26: #include "syntax.h"
27:
28: Lisp_Object Qsyntax_table_p;
29:
30: DEFUN ("syntax-table-p", Fsyntax_table_p, Ssyntax_table_p, 1, 1, 0,
31: "Return t if ARG is a syntax table.\n\
32: Any vector of 256 elements will do.")
33: (obj)
34: Lisp_Object obj;
35: {
36: if (XTYPE (obj) == Lisp_Vector && XVECTOR (obj)->size == 0400)
37: return Qt;
38: return Qnil;
39: }
40:
41: Lisp_Object
42: check_syntax_table (obj)
43: Lisp_Object obj;
44: {
45: register Lisp_Object tem;
46: while (tem = Fsyntax_table_p (obj),
47: NULL (tem))
48: obj = wrong_type_argument (Qsyntax_table_p, obj, 0);
49: return obj;
50: }
51:
52:
53: DEFUN ("syntax-table", Fsyntax_table, Ssyntax_table, 0, 0, 0,
54: "Return the current syntax table.\n\
55: This is the one specified by the current buffer.")
56: ()
57: {
58: return current_buffer->syntax_table;
59: }
60:
61: DEFUN ("standard-syntax-table", Fstandard_syntax_table,
62: Sstandard_syntax_table, 0, 0, 0,
63: "Return the standard syntax table.\n\
64: This is the one used for new buffers.")
65: ()
66: {
67: return Vstandard_syntax_table;
68: }
69:
70: DEFUN ("copy-syntax-table", Fcopy_syntax_table, Scopy_syntax_table, 0, 1, 0,
71: "Construct a new syntax table and return it.\n\
72: It is a copy of the TABLE, which defaults to the standard syntax table.")
73: (table)
74: Lisp_Object table;
75: {
76: Lisp_Object size, val;
77: XFASTINT (size) = 0400;
78: XFASTINT (val) = 0;
79: val = Fmake_vector (size, val);
80: if (!NULL (table))
81: table = check_syntax_table (table);
82: else if (NULL (Vstandard_syntax_table))
83: /* Can only be null during initialization */
84: return val;
85: else table = Vstandard_syntax_table;
86:
87: bcopy (XVECTOR (table)->contents,
88: XVECTOR (val)->contents, 0400 * sizeof (Lisp_Object));
89: return val;
90: }
91:
92: DEFUN ("set-syntax-table", Fset_syntax_table, Sset_syntax_table, 1, 1, 0,
93: "Select a new syntax table for the current buffer.\n\
94: One argument, a syntax table.")
95: (table)
96: Lisp_Object table;
97: {
98: table = check_syntax_table (table);
99: current_buffer->syntax_table = table;
100: /* Indicate that this buffer now has a specified syntax table. */
101: current_buffer->local_var_flags |= buffer_local_flags.syntax_table;
102: return table;
103: }
104:
105: /* Convert a letter which signifies a syntax code
106: into the code it signifies.
107: This is used by modify-syntax-entry, and other things. */
108:
109: unsigned char syntax_spec_code[0400] =
110: { 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377,
111: 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377,
112: 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377,
113: 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377,
114: (char) Swhitespace, 0377, (char) Sstring, 0377,
115: (char) Smath, 0377, 0377, (char) Squote,
116: (char) Sopen, (char) Sclose, 0377, 0377,
117: 0377, (char) Swhitespace, (char) Spunct, (char) Scharquote,
118: 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377,
119: 0377, 0377, 0377, 0377,
120: (char) Scomment, 0377, (char) Sendcomment, 0377,
121: 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, /* @, A, ... */
122: 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377,
123: 0377, 0377, 0377, 0377, 0377, 0377, 0377, (char) Sword,
124: 0377, 0377, 0377, 0377, (char) Sescape, 0377, 0377, (char) Ssymbol,
125: 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377, /* `, a, ... */
126: 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377,
127: 0377, 0377, 0377, 0377, 0377, 0377, 0377, (char) Sword,
128: 0377, 0377, 0377, 0377, 0377, 0377, 0377, 0377
129: };
130:
131: /* Indexed by syntax code, give the letter that describes it. */
132:
133: char syntax_code_spec[13] =
134: {
135: ' ', '.', 'w', '_', '(', ')', '\'', '\"', '$', '\\', '/', '<', '>'
136: };
137:
138: DEFUN ("char-syntax", Fchar_syntax, Schar_syntax, 1, 1, 0,
139: "Return the syntax code of CHAR, described by a character.\n\
140: For example, if CHAR is a word constituent, ?w is returned.\n\
141: The characters that correspond to various syntax codes\n\
142: are listed in the documentation of modify-syntax-entry.")
143: (ch)
144: Lisp_Object ch;
145: {
146: CHECK_NUMBER (ch, 0);
147: return make_number (syntax_code_spec[(int) SYNTAX (0xFF & XINT (ch))]);
148: }
149:
150: /* This comment supplies the doc string for modify-syntax-entry,
151: for make-docfile to see. We cannot put this in the real DEFUN
152: due to limits in the Unix cpp.
153:
154: DEFUN ("modify-syntax-entry", foo, bar, 0, 0, 0,
155: "Set syntax for character CHAR according to string S.\n\
156: The syntax is changed only for table TABLE, which defaults to\n\
157: the current buffer's syntax table.\n\
158: The first character of S should be one of the following:\n\
159: Space or - whitespace syntax. w word constituent.\n\
160: _ symbol constituent. . punctuation.\n\
161: ( open-parenthesis. ) close-parenthesis.\n\
162: \" string quote. \\ escape character.\n\
163: $ paired delimiter. ' expression prefix operator.\n\
164: < comment starter. > comment ender.\n\
165: / character quote.\n\
166: Only single-character comment start and end sequences are represented thus.\n\
167: Two-character sequences are represented as described below.\n\
168: The second character of S is the matching parenthesis,\n\
169: used only if the first character is ( or ).\n\
170: Any additional characters are flags.\n\
171: Defined flags are the characters 1, 2, 3 and 4.\n\
172: 1 means C is the start of a two-char comment start sequence.\n\
173: 2 means C is the second character of such a sequence.\n\
174: 3 means C is the start of a two-char comment end sequence.\n\
175: 4 means C is the second character of such a sequence.")
176:
177: */
178:
179: DEFUN ("modify-syntax-entry", Fmodify_syntax_entry, Smodify_syntax_entry, 2, 3,
180: /* I really don't know why this is interactive
181: help-form should at least be made useful whilst reading the second arg
182: */
183: "cSet syntax for character: \nsSet syntax for %s to: ",
184: 0 /* See immediately above */)
185: (c, newentry, syntax_table)
186: Lisp_Object c, newentry, syntax_table;
187: {
188: register unsigned char *p, match;
189: register enum syntaxcode code;
190: Lisp_Object val;
191:
192: CHECK_NUMBER (c, 0);
193: CHECK_STRING (newentry, 1);
194: if (NULL (syntax_table))
195: syntax_table = current_buffer->syntax_table;
196: else
197: syntax_table = check_syntax_table (syntax_table);
198:
199: p = XSTRING (newentry)->data;
200: code = (enum syntaxcode) syntax_spec_code[*p++];
201: if (((int) code & 0377) == 0377)
202: error ("invalid syntax description letter: %c", c);
203:
204: match = *p;
205: if (match) p++;
206: if (match == ' ') match = 0;
207:
208: XFASTINT (val) = (match << 8) + (int) code;
209: while (*p)
210: switch (*p++)
211: {
212: case '1':
213: XFASTINT (val) |= 1 << 16;
214: break;
215:
216: case '2':
217: XFASTINT (val) |= 1 << 17;
218: break;
219:
220: case '3':
221: XFASTINT (val) |= 1 << 18;
222: break;
223:
224: case '4':
225: XFASTINT (val) |= 1 << 19;
226: break;
227: }
228:
229: XVECTOR (syntax_table)->contents[0xFF & XINT (c)] = val;
230:
231: return Qnil;
232: }
233:
234: /* Dump syntax table to buffer in human-readable format */
235:
236: describe_syntax (value)
237: Lisp_Object value;
238: {
239: register enum syntaxcode code;
240: char desc, match, start1, start2, end1, end2;
241: char str[2];
242:
243: Findent_to (make_number (16), make_number (1));
244:
245: if (XTYPE (value) != Lisp_Int)
246: {
247: InsStr ("invalid");
248: return;
249: }
250:
251: code = (enum syntaxcode) (XINT (value) & 0377);
252: match = (XINT (value) >> 8) & 0377;
253: start1 = (XINT (value) >> 16) & 1;
254: start2 = (XINT (value) >> 17) & 1;
255: end1 = (XINT (value) >> 18) & 1;
256: end2 = (XINT (value) >> 19) & 1;
257:
258: if ((int) code < 0 || (int) code >= (int) Smax)
259: {
260: InsStr ("invalid");
261: return;
262: }
263: desc = syntax_code_spec[(int) code];
264:
265: str[0] = desc, str[1] = 0;
266: insert (str, 1);
267:
268: str[0] = match ? match : ' ';
269: insert (str, 1);
270:
271:
272: if (start1)
273: insert ("1", 1);
274: if (start2)
275: insert ("2", 1);
276:
277: if (end1)
278: insert ("3", 1);
279: if (end2)
280: insert ("4", 1);
281:
282: InsStr ("\twhich means: ");
283:
284: #ifdef SWITCH_ENUM_BUG
285: switch ((int) code)
286: #else
287: switch (code)
288: #endif
289: {
290: case Swhitespace:
291: InsStr ("whitespace"); break;
292: case Spunct:
293: InsStr ("punctuation"); break;
294: case Sword:
295: InsStr ("word"); break;
296: case Ssymbol:
297: InsStr ("symbol"); break;
298: case Sopen:
299: InsStr ("open"); break;
300: case Sclose:
301: InsStr ("close"); break;
302: case Squote:
303: InsStr ("quote"); break;
304: case Sstring:
305: InsStr ("string"); break;
306: case Smath:
307: InsStr ("math"); break;
308: case Sescape:
309: InsStr ("escape"); break;
310: case Scharquote:
311: InsStr ("charquote"); break;
312: case Scomment:
313: InsStr ("comment"); break;
314: case Sendcomment:
315: InsStr ("endcomment"); break;
316: default:
317: InsStr ("invalid");
318: return;
319: }
320:
321: if (match)
322: {
323: InsStr (", matches ");
324:
325: str[0] = match, str[1] = 0;
326: insert (str, 1);
327: }
328:
329: if (start1)
330: InsStr (",\n\t is the first character of a comment-start sequence");
331: if (start2)
332: InsStr (",\n\t is the second character of a comment-start sequence");
333:
334: if (end1)
335: InsStr (",\n\t is the first character of a comment-end sequence");
336: if (end2)
337: InsStr (",\n\t is the second character of a comment-end sequence");
338:
339: InsStr ("\n");
340: }
341:
342: Lisp_Object
343: describe_syntax_1 (vector)
344: Lisp_Object vector;
345: {
346: struct buffer *old = current_buffer;
347: set_buffer_internal (XBUFFER (Vstandard_output));
348: describe_vector (vector, Qnil, describe_syntax, 0, Qnil);
349: set_buffer_internal (old);
350: return Qnil;
351: }
352:
353: DEFUN ("describe-syntax", Fdescribe_syntax, Sdescribe_syntax, 0, 0, "",
354: "Describe the syntax specifications in the syntax table.\n\
355: The descriptions are inserted in a buffer, which is selected so you can see it.")
356: ()
357: {
358: internal_with_output_to_temp_buffer
359: ("*Help*", describe_syntax_1, current_buffer->syntax_table);
360:
361: return Qnil;
362: }
363:
364: /* Return the position across `count' words from `from'.
365: If that many words cannot be found before the end of the buffer, return 0.
366: `count' negative means scan backward and stop at word beginning. */
367:
368: scan_words (from, count)
369: register int from, count;
370: {
371: register int beg = BEGV;
372: register int end = ZV;
373:
374: immediate_quit = 1;
375: QUIT;
376:
377: while (count > 0)
378: {
379: while (1)
380: {
381: if (from == end)
382: {
383: immediate_quit = 0;
384: return 0;
385: }
386: if (SYNTAX(FETCH_CHAR (from)) == Sword)
387: break;
388: from++;
389: }
390: while (1)
391: {
392: if (from == end) break;
393: if (SYNTAX(FETCH_CHAR (from)) != Sword)
394: break;
395: from++;
396: }
397: count--;
398: }
399: while (count < 0)
400: {
401: while (1)
402: {
403: if (from == beg)
404: {
405: immediate_quit = 0;
406: return 0;
407: }
408: if (SYNTAX(FETCH_CHAR (from - 1)) == Sword)
409: break;
410: from--;
411: }
412: while (1)
413: {
414: if (from == beg) break;
415: if (SYNTAX(FETCH_CHAR (from - 1)) != Sword)
416: break;
417: from--;
418: }
419: count++;
420: }
421:
422: immediate_quit = 0;
423:
424: return from;
425: }
426:
427: DEFUN ("forward-word", Fforward_word, Sforward_word, 1, 1, "p",
428: "Move point forward ARG words (backward if ARG is negative).\n\
429: Normally returns t.\n\
430: If an edge of the buffer is reached, point is left there\n\
431: and nil is returned.")
432: (count)
433: Lisp_Object count;
434: {
435: int val;
436: CHECK_NUMBER (count, 0);
437:
438: if (!(val = scan_words (point, XINT (count))))
439: {
440: SET_PT (XINT (count) > 0 ? ZV : BEGV);
441: return Qnil;
442: }
443: SET_PT (val);
444: return Qt;
445: }
446:
447: int parse_sexp_ignore_comments;
448:
449: Lisp_Object
450: scan_lists (from, count, depth, sexpflag)
451: register int from;
452: int count, depth, sexpflag;
453: {
454: Lisp_Object val;
455: register int stop;
456: register int c;
457: char stringterm;
458: int quoted;
459: int mathexit = 0;
460: register enum syntaxcode code;
461: int min_depth = depth; /* Err out if depth gets less than this. */
462:
463: if (depth > 0) min_depth = 0;
464:
465: immediate_quit = 1;
466: QUIT;
467:
468: while (count > 0)
469: {
470: stop = ZV;
471: while (from < stop)
472: {
473: c = FETCH_CHAR (from);
474: code = SYNTAX(c);
475: from++;
476: if (from < stop && SYNTAX_COMSTART_FIRST (c)
477: && SYNTAX_COMSTART_SECOND (FETCH_CHAR (from))
478: && parse_sexp_ignore_comments)
479: code = Scomment, from++;
480:
481: #ifdef SWITCH_ENUM_BUG
482: switch ((int) code)
483: #else
484: switch (code)
485: #endif
486: {
487: case Sescape:
488: case Scharquote:
489: if (from == stop) goto lose;
490: from++;
491: /* treat following character as a word constituent */
492: case Sword:
493: case Ssymbol:
494: if (depth || !sexpflag) break;
495: /* This word counts as a sexp; return at end of it. */
496: while (from < stop)
497: {
498: #ifdef SWITCH_ENUM_BUG
499: switch ((int) SYNTAX(FETCH_CHAR (from)))
500: #else
501: switch (SYNTAX(FETCH_CHAR (from)))
502: #endif
503: {
504: case Scharquote:
505: case Sescape:
506: from++;
507: if (from == stop) goto lose;
508: break;
509: case Sword:
510: case Ssymbol:
511: case Squote:
512: break;
513: default:
514: goto done;
515: }
516: from++;
517: }
518: goto done;
519:
520: case Scomment:
521: if (!parse_sexp_ignore_comments) break;
522: while (1)
523: {
524: if (from == stop) goto done;
525: if (SYNTAX (c = FETCH_CHAR (from)) == Sendcomment)
526: break;
527: from++;
528: if (from < stop && SYNTAX_COMEND_FIRST (c)
529: && SYNTAX_COMEND_SECOND (FETCH_CHAR (from)))
530: { from++; break; }
531: }
532: break;
533:
534: case Smath:
535: if (!sexpflag)
536: break;
537: if (from != stop && c == FETCH_CHAR (from))
538: from++;
539: if (mathexit)
540: {
541: mathexit = 0;
542: goto close1;
543: }
544: mathexit = 1;
545:
546: case Sopen:
547: if (!++depth) goto done;
548: break;
549:
550: case Sclose:
551: close1:
552: if (!--depth) goto done;
553: if (depth < min_depth)
554: error ("Containing expression ends prematurely");
555: break;
556:
557: case Sstring:
558: stringterm = FETCH_CHAR (from - 1);
559: while (1)
560: {
561: if (from >= stop) goto lose;
562: if (FETCH_CHAR (from) == stringterm) break;
563: #ifdef SWITCH_ENUM_BUG
564: switch ((int) SYNTAX(FETCH_CHAR (from)))
565: #else
566: switch (SYNTAX(FETCH_CHAR (from)))
567: #endif
568: {
569: case Scharquote:
570: case Sescape:
571: from++;
572: }
573: from++;
574: }
575: from++;
576: if (!depth && sexpflag) goto done;
577: break;
578: }
579: }
580:
581: /* Reached end of buffer. Error if within object, return nil if between */
582: if (depth) goto lose;
583:
584: immediate_quit = 0;
585: return Qnil;
586:
587: /* End of object reached */
588: done:
589: count--;
590: }
591:
592: while (count < 0)
593: {
594: stop = BEGV;
595: while (from > stop)
596: {
597: from--;
598: if (quoted = char_quoted (from))
599: from--;
600: c = FETCH_CHAR (from);
601: code = SYNTAX (c);
602: if (from > stop && SYNTAX_COMEND_SECOND (c)
603: && SYNTAX_COMEND_FIRST (FETCH_CHAR (from - 1))
604: && !char_quoted (from - 1)
605: && parse_sexp_ignore_comments)
606: code = Sendcomment, from--;
607:
608: #ifdef SWITCH_ENUM_BUG
609: switch ((int) (quoted ? Sword : code))
610: #else
611: switch (quoted ? Sword : code)
612: #endif
613: {
614: case Sword:
615: case Ssymbol:
616: if (depth || !sexpflag) break;
617: /* This word counts as a sexp; count object finished after passing it. */
618: while (from > stop)
619: {
620: if (quoted = char_quoted (from - 1))
621: from--;
622: if (! (quoted || SYNTAX(FETCH_CHAR (from - 1)) == Sword ||
623: SYNTAX(FETCH_CHAR (from - 1)) == Ssymbol ||
624: SYNTAX(FETCH_CHAR (from - 1)) == Squote))
625: goto done2;
626: from--;
627: }
628: goto done2;
629:
630: case Smath:
631: if (!sexpflag)
632: break;
633: if (from != stop && c == FETCH_CHAR (from - 1))
634: from--;
635: if (mathexit)
636: {
637: mathexit = 0;
638: goto open2;
639: }
640: mathexit = 1;
641:
642: case Sclose:
643: if (!++depth) goto done2;
644: break;
645:
646: case Sopen:
647: open2:
648: if (!--depth) goto done2;
649: if (depth < min_depth)
650: error ("Containing expression ends prematurely");
651: break;
652:
653: case Sendcomment:
654: if (!parse_sexp_ignore_comments) break;
655: if (from != stop) from--;
656: while (1)
657: {
658: if (SYNTAX (c = FETCH_CHAR (from)) == Scomment)
659: break;
660: if (from == stop) goto done;
661: from--;
662: if (SYNTAX_COMSTART_SECOND (c)
663: && SYNTAX_COMSTART_FIRST (FETCH_CHAR (from))
664: && !char_quoted (from))
665: break;
666: }
667: break;
668:
669: case Sstring:
670: stringterm = FETCH_CHAR (from);
671: while (1)
672: {
673: if (from == stop) goto lose;
674: if (!char_quoted (from - 1)
675: && stringterm == FETCH_CHAR (from - 1))
676: break;
677: from--;
678: }
679: from--;
680: if (!depth && sexpflag) goto done2;
681: break;
682: }
683: }
684:
685: /* Reached start of buffer. Error if within object, return nil if between */
686: if (depth) goto lose;
687:
688: immediate_quit = 0;
689: return Qnil;
690:
691: done2:
692: count++;
693: }
694:
695:
696: immediate_quit = 0;
697: XFASTINT (val) = from;
698: return val;
699:
700: lose:
701: error ("Unbalanced parentheses");
702: /* NOTREACHED */
703: }
704:
705: char_quoted (pos)
706: register int pos;
707: {
708: register enum syntaxcode code;
709: register int beg = BEGV;
710: register int quoted = 0;
711:
712: while (pos > beg &&
713: ((code = SYNTAX (FETCH_CHAR (pos - 1))) == Scharquote
714: || code == Sescape))
715: pos--, quoted = !quoted;
716: return quoted;
717: }
718:
719: DEFUN ("scan-lists", Fscan_lists, Sscan_lists, 3, 3, 0,
720: "Scan from character number FROM by COUNT lists.\n\
721: Returns the character number of the position thus found.\n\
722: \n\
723: If DEPTH is nonzero, paren depth begins counting from that value,\n\
724: only places where the depth in parentheses becomes zero\n\
725: are candidates for stopping; COUNT such places are counted.\n\
726: Thus, a positive value for DEPTH means go out levels.\n\
727: \n\
728: Comments are ignored if parse-sexp-ignore-comments is non-nil.\n\
729: \n\
730: If the beginning or end of (the visible part of) the buffer is reached\n\
731: and the depth is wrong, an error is signaled.\n\
732: If the depth is right but the count is not used up, nil is returned.")
733: (from, count, depth)
734: Lisp_Object from, count, depth;
735: {
736: CHECK_NUMBER (from, 0);
737: CHECK_NUMBER (count, 1);
738: CHECK_NUMBER (depth, 2);
739:
740: return scan_lists (XINT (from), XINT (count), XINT (depth), 0);
741: }
742:
743: DEFUN ("scan-sexps", Fscan_sexps, Sscan_sexps, 2, 2, 0,
744: "Scan from character number FROM by COUNT balanced expressions.\n\
745: Returns the character number of the position thus found.\n\
746: \n\
747: Comments are ignored if parse-sexp-ignore-comments is non-nil.\n\
748: \n\
749: If the beginning or end of (the visible part of) the buffer is reached\n\
750: in the middle of a parenthetical grouping, an error is signaled.\n\
751: If the beginning or end is reached between groupings but before count is used up,\n\
752: nil is returned.")
753: (from, count)
754: Lisp_Object from, count;
755: {
756: CHECK_NUMBER (from, 0);
757: CHECK_NUMBER (count, 1);
758:
759: return scan_lists (XINT (from), XINT (count), 0, 1);
760: }
761:
762: DEFUN ("backward-prefix-chars", Fbackward_prefix_chars, Sbackward_prefix_chars,
763: 0, 0, 0,
764: "Move point backward over any number of chars with syntax \"prefix\".")
765: ()
766: {
767: int beg = BEGV;
768: int pos = point;
769:
770: while (pos > beg && !char_quoted (pos - 1) && SYNTAX (FETCH_CHAR (pos - 1)) == Squote)
771: pos--;
772:
773: SET_PT (pos);
774:
775: return Qnil;
776: }
777:
778: struct lisp_parse_state
779: {
780: int depth; /* Depth at end of parsing */
781: int instring; /* -1 if not within string, else desired terminator. */
782: int incomment; /* Nonzero if within a comment at end of parsing */
783: int quoted; /* Nonzero if just after an escape char at end of parsing */
784: int thislevelstart; /* Char number of most recent start-of-expression at current level */
785: int prevlevelstart; /* Char number of start of containing expression */
786: int location; /* Char number at which parsing stopped. */
787: int mindepth; /* Minimum depth seen while scanning. */
788: };
789:
790: /* Parse forward from FROM to END,
791: assuming that FROM is the start of a function,
792: and return a description of the state of the parse at END. */
793:
794: struct lisp_parse_state val_scan_sexps_forward;
795:
796: struct lisp_parse_state *
797: scan_sexps_forward (from, end, targetdepth, stopbefore, oldstate)
798: register int from;
799: int end, targetdepth, stopbefore;
800: Lisp_Object oldstate;
801: {
802: struct lisp_parse_state state;
803:
804: register enum syntaxcode code;
805: struct level { int last, prev; };
806: struct level levelstart[100];
807: register struct level *curlevel = levelstart;
808: struct level *endlevel = levelstart + 100;
809: char prev;
810: register int depth; /* Paren depth of current scanning location.
811: level - levelstart equals this except
812: when the depth becomes negative. */
813: int mindepth; /* Lowest DEPTH value seen. */
814: int start_quoted = 0; /* Nonzero means starting after a char quote */
815: Lisp_Object tem;
816:
817: immediate_quit = 1;
818: QUIT;
819:
820: if (NULL (oldstate))
821: {
822: depth = 0;
823: state.instring = -1;
824: state.incomment = 0;
825: }
826: else
827: {
828: tem = Fcar (oldstate);
829: if (!NULL (tem))
830: depth = XINT (tem);
831: else
832: depth = 0;
833:
834: oldstate = Fcdr (oldstate);
835: oldstate = Fcdr (oldstate);
836: oldstate = Fcdr (oldstate);
837: tem = Fcar (oldstate);
838: state.instring = !NULL (tem) ? XINT (tem) : -1;
839:
840: oldstate = Fcdr (oldstate);
841: tem = Fcar (oldstate);
842: state.incomment = !NULL (tem);
843:
844: oldstate = Fcdr (oldstate);
845: tem = Fcar (oldstate);
846: start_quoted = !NULL (tem);
847: }
848: state.quoted = 0;
849: mindepth = depth;
850:
851: curlevel->prev = -1;
852: curlevel->last = -1;
853:
854: /* Enter the loop at a place appropriate for initial state. */
855:
856: if (state.incomment) goto startincomment;
857: if (state.instring >= 0)
858: {
859: if (start_quoted) goto startquotedinstring;
860: goto startinstring;
861: }
862: if (start_quoted) goto startquoted;
863:
864: while (from < end)
865: {
866: code = SYNTAX(FETCH_CHAR (from));
867: from++;
868: if (from < end && SYNTAX_COMSTART_FIRST (FETCH_CHAR (from - 1))
869: && SYNTAX_COMSTART_SECOND (FETCH_CHAR (from)))
870: code = Scomment, from++;
871: #ifdef SWITCH_ENUM_BUG
872: switch ((int) code)
873: #else
874: switch (code)
875: #endif
876: {
877: case Sescape:
878: case Scharquote:
879: if (stopbefore) goto stop; /* this arg means stop at sexp start */
880: curlevel->last = from - 1;
881: startquoted:
882: if (from == end) goto endquoted;
883: from++;
884: goto symstarted;
885: /* treat following character as a word constituent */
886: case Sword:
887: case Ssymbol:
888: if (stopbefore) goto stop; /* this arg means stop at sexp start */
889: curlevel->last = from - 1;
890: symstarted:
891: while (from < end)
892: {
893: #ifdef SWITCH_ENUM_BUG
894: switch ((int) SYNTAX(FETCH_CHAR (from)))
895: #else
896: switch (SYNTAX(FETCH_CHAR (from)))
897: #endif
898: {
899: case Scharquote:
900: case Sescape:
901: from++;
902: if (from == end) goto endquoted;
903: break;
904: case Sword:
905: case Ssymbol:
906: case Squote:
907: break;
908: default:
909: goto symdone;
910: }
911: from++;
912: }
913: symdone:
914: curlevel->prev = curlevel->last;
915: break;
916:
917: case Scomment:
918: state.incomment = 1;
919: startincomment:
920: while (1)
921: {
922: if (from == end) goto done;
923: if (SYNTAX (prev = FETCH_CHAR (from)) == Sendcomment)
924: break;
925: from++;
926: if (from < end && SYNTAX_COMEND_FIRST (prev)
927: && SYNTAX_COMEND_SECOND (FETCH_CHAR (from)))
928: { from++; break; }
929: }
930: state.incomment = 0;
931: break;
932:
933: case Sopen:
934: if (stopbefore) goto stop; /* this arg means stop at sexp start */
935: depth++;
936: /* curlevel++->last ran into compiler bug on Apollo */
937: curlevel->last = from - 1;
938: if (++curlevel == endlevel)
939: error ("Nesting too deep for parser");
940: curlevel->prev = -1;
941: curlevel->last = -1;
942: if (!--targetdepth) goto done;
943: break;
944:
945: case Sclose:
946: depth--;
947: if (depth < mindepth)
948: mindepth = depth;
949: if (curlevel != levelstart)
950: curlevel--;
951: curlevel->prev = curlevel->last;
952: if (!++targetdepth) goto done;
953: break;
954:
955: case Sstring:
956: if (stopbefore) goto stop; /* this arg means stop at sexp start */
957: curlevel->last = from - 1;
958: state.instring = FETCH_CHAR (from - 1);
959: startinstring:
960: while (1)
961: {
962: if (from >= end) goto done;
963: if (FETCH_CHAR (from) == state.instring) break;
964: #ifdef SWITCH_ENUM_BUG
965: switch ((int) SYNTAX(FETCH_CHAR (from)))
966: #else
967: switch (SYNTAX(FETCH_CHAR (from)))
968: #endif
969: {
970: case Scharquote:
971: case Sescape:
972: from++;
973: startquotedinstring:
974: if (from >= end) goto endquoted;
975: }
976: from++;
977: }
978: state.instring = -1;
979: curlevel->prev = curlevel->last;
980: from++;
981: break;
982:
983: case Smath:
984: break;
985: }
986: }
987: goto done;
988:
989: stop: /* Here if stopping before start of sexp. */
990: from--; /* We have just fetched the char that starts it; */
991: goto done; /* but return the position before it. */
992:
993: endquoted:
994: state.quoted = 1;
995: done:
996: state.depth = depth;
997: state.mindepth = mindepth;
998: state.thislevelstart = curlevel->prev;
999: state.prevlevelstart
1000: = (curlevel == levelstart) ? -1 : (curlevel - 1)->last;
1001: state.location = from;
1002: immediate_quit = 0;
1003:
1004: val_scan_sexps_forward = state;
1005: return &val_scan_sexps_forward;
1006: }
1007:
1008: /* This comment supplies the doc string for parse-partial-sexp,
1009: for make-docfile to see. We cannot put this in the real DEFUN
1010: due to limits in the Unix cpp.
1011:
1012: DEFUN ("parse-partial-sexp", Ffoo, Sfoo, 0, 0, 0,
1013: "Parse Lisp syntax starting at FROM until TO; return status of parse at TO.\n\
1014: Parsing stops at TO or when certain criteria are met;\n\
1015: point is set to where parsing stops.\n\
1016: If fifth arg STATE is omitted or nil,\n\
1017: parsing assumes that FROM is the beginning of a function.\n\
1018: Value is a list of seven elements describing final state of parsing:\n\
1019: 1. depth in parens.\n\
1020: 2. character address of start of innermost containing list; nil if none.\n\
1021: 3. character address of start of last complete sexp terminated.\n\
1022: 4. non-nil if inside a string.\n\
1023: (it is the character that will terminate the string.)\n\
1024: 5. t if inside a comment.\n\
1025: 6. t if following a quote character.\n\
1026: 7. the minimum paren-depth encountered during this scan.\n\
1027: If third arg TARGETDEPTH is non-nil, parsing stops if the depth\n\
1028: in parentheses becomes equal to TARGETDEPTH.\n\
1029: Fourth arg STOPBEFORE non-nil means stop when come to\n\
1030: any character that starts a sexp.\n\
1031: Fifth arg STATE is a seven-list like what this function returns.\n\
1032: It is used to initialize the state of the parse.")
1033:
1034: */
1035:
1036: DEFUN ("parse-partial-sexp", Fparse_partial_sexp, Sparse_partial_sexp, 2, 5, 0,
1037: 0 /* See immediately above */)
1038: (from, to, targetdepth, stopbefore, oldstate)
1039: Lisp_Object from, to, targetdepth, stopbefore, oldstate;
1040: {
1041: struct lisp_parse_state state;
1042: int target;
1043:
1044: if (!NULL (targetdepth))
1045: {
1046: CHECK_NUMBER (targetdepth, 3);
1047: target = XINT (targetdepth);
1048: }
1049: else
1050: target = -100000; /* We won't reach this depth */
1051:
1052: validate_region (&from, &to);
1053: state = *scan_sexps_forward (XINT (from), XINT (to),
1054: target, !NULL (stopbefore), oldstate);
1055:
1056: SET_PT (state.location);
1057:
1058: return Fcons (make_number (state.depth),
1059: Fcons (state.prevlevelstart < 0 ? Qnil : make_number (state.prevlevelstart),
1060: Fcons (state.thislevelstart < 0 ? Qnil : make_number (state.thislevelstart),
1061: Fcons (state.instring >= 0 ? make_number (state.instring) : Qnil,
1062: Fcons (state.incomment ? Qt : Qnil,
1063: Fcons (state.quoted ? Qt : Qnil,
1064: Fcons (make_number (state.mindepth), Qnil)))))));
1065: }
1066:
1067: init_syntax_once ()
1068: {
1069: register int i;
1070: register struct Lisp_Vector *v;
1071:
1072: /* Set this now, so first buffer creation can refer to it. */
1073: /* Make it nil before calling copy-syntax-table
1074: so that copy-syntax-table will know not to try to copy from garbage */
1075: Vstandard_syntax_table = Qnil;
1076: Vstandard_syntax_table = Fcopy_syntax_table (Qnil);
1077:
1078: v = XVECTOR (Vstandard_syntax_table);
1079:
1080: for (i = 'a'; i <= 'z'; i++)
1081: XFASTINT (v->contents[i]) = (int) Sword;
1082: for (i = 'A'; i <= 'Z'; i++)
1083: XFASTINT (v->contents[i]) = (int) Sword;
1084: for (i = '0'; i <= '9'; i++)
1085: XFASTINT (v->contents[i]) = (int) Sword;
1086: XFASTINT (v->contents['$']) = (int) Sword;
1087: XFASTINT (v->contents['%']) = (int) Sword;
1088:
1089: XFASTINT (v->contents['(']) = (int) Sopen + (')' << 8);
1090: XFASTINT (v->contents[')']) = (int) Sclose + ('(' << 8);
1091: XFASTINT (v->contents['[']) = (int) Sopen + (']' << 8);
1092: XFASTINT (v->contents[']']) = (int) Sclose + ('[' << 8);
1093: XFASTINT (v->contents['{']) = (int) Sopen + ('}' << 8);
1094: XFASTINT (v->contents['}']) = (int) Sclose + ('{' << 8);
1095: XFASTINT (v->contents['"']) = (int) Sstring;
1096: XFASTINT (v->contents['\\']) = (int) Sescape;
1097:
1098: for (i = 0; i < 10; i++)
1099: XFASTINT (v->contents["_-+*/&|<>="[i]]) = (int) Ssymbol;
1100:
1101: for (i = 0; i < 12; i++)
1102: XFASTINT (v->contents[".,;:?!#@~^'`"[i]]) = (int) Spunct;
1103: }
1104:
1105: syms_of_syntax ()
1106: {
1107: Qsyntax_table_p = intern ("syntax-table-p");
1108: staticpro (&Qsyntax_table_p);
1109:
1110: DEFVAR_BOOL ("parse-sexp-ignore-comments", &parse_sexp_ignore_comments,
1111: "Non-nil means forward-sexp, etc., should treat comments as whitespace.\n\
1112: Non-nil works only when the comment terminator is something like *\/,\n\
1113: and appears only when it ends a comment.\n\
1114: If comments are terminated by newlines,\n\
1115: you must make this variable nil.");
1116:
1117: defsubr (&Ssyntax_table_p);
1118: defsubr (&Ssyntax_table);
1119: defsubr (&Sstandard_syntax_table);
1120: defsubr (&Scopy_syntax_table);
1121: defsubr (&Sset_syntax_table);
1122: defsubr (&Schar_syntax);
1123: defsubr (&Smodify_syntax_entry);
1124: defsubr (&Sdescribe_syntax);
1125:
1126: defsubr (&Sforward_word);
1127:
1128: defsubr (&Sscan_lists);
1129: defsubr (&Sscan_sexps);
1130: defsubr (&Sbackward_prefix_chars);
1131: defsubr (&Sparse_partial_sexp);
1132: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.