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