chris@umcp-cs (12/19/83)
Here's a new and improved version of ParenScan, the paren matcher, with new and improved bugs (just kidding) for your Gosling Emacs (either #85 or #264). This one understands comments. I've also included two minor changes that make dump-syntax-table perform name completion. While it can now correctly match the {} in foo () { /* comment's got an apostrophe */ ... } ParenScan still has trouble with ``nested'' comments such as bar () { /* int i; /* not used */ } because it can't tell, when scanning backwards, that the second "/*" is still within an enclosing "/*". This is usually not a problem. You will have to modify your electric-c mode to define /* and */ as comment characters, with (modify-syntax-entry " { */") ; /, with *, begins comments: /* (modify-syntax-entry " }/*") ; *, with /, ends comments: */ Equivalent changes should be made to mlisp and lisp modes to make them start comments with ; and end them with \n. First, ParenScan: ----------------------------------------------------------------------- /* Primitive function for paren matching. Leaves dot at enclosing left paren, or at top of buffer if none. Stops at a zero-level newline if StopAtNewline is set. Returns (to MLisp) 1 if it finds a match, 0 if not. */ /* Bug: if the stop-comment auxil character is also a quote, paren, or prefix quote, reverse scans will sometimes be wrong. */ static ParenScan (StopAtNewline, forward) { register struct SyntaxTable *s = bf_mode.md_syntax; register enum SyntaxKinds k; register c, pc, on_on = 1, ParenLevel = 0; char parenstack[200]; int InString = 0, InComment = 0, MatchingQuote, delta = 1; MLvalue -> exp_type = IsInteger; MLvalue -> exp_int = 0; if (forward != 0 && forward != 1) { error ("panic: ParenScan"); return 0; } if (StopAtNewline) { /* Skip over whitespace */ pc = dot - 1; if (forward) while (pc < NumCharacters) { if ((c = CharAt (pc)) != ' ' && c != '\t' && c != '\n') break; pc++; } else while (pc > FirstCharacter) { if ((c = CharAt (pc)) != ' ' && c != '\t' && c != '\n') break; pc--; } SetDot (pc + 1); } /* Scan through buffer until done or error */ while (on_on && !err) { if (forward) { if (dot > NumCharacters) return 0; DotRight (delta); delta = 1; } else if (dot <= FirstCharacter) return 0; c = CharAt (dot - 1); /* If in a comment, see if we are now out. If not in a comment, see if we are now in. The comparisons to forward account for the fact that reverse scans start comments on seeing the end-comment character, and end comments on seeing the start-comment character. */ /* The bug is in here: we should look at (dot-2) for two-character end-comment strings when doing reverse scans, not at (dot-1). I don't think it's worth the effort. */ if (InComment != forward && s -> s_table[c].BeginComment || InComment == forward && s -> s_table[c].EndComment) { if ((pc = s -> s_table[c].CommentAux) == 0) { InComment = !InComment; goto advance; } if (dot <= NumCharacters && pc == CharAt (dot)) { if (forward) delta++; InComment = !InComment; goto advance; } } /* If in a comment, just continue on */ if (InComment) goto advance; /* See what kind of character we have. Carefully check for quoted quotes (and even for quoted quoters but no further; this takes care of things like "'\''" and "'\\'"). */ k = s -> s_table[c].s_kind; if (dot > 2 && s -> s_table[CharAt (dot-2)].s_kind == PrefixQuote && (dot==3 || s -> s_table[CharAt (dot-3)].s_kind != PrefixQuote)) k = WordChar; if (k == PairedQuote) { if (!InString) /* start quotes */ InString++, MatchingQuote = c; else /* end quotes (if it's the same quote) */ if (c == MatchingQuote) InString = 0; } if (c == '\n' && ParenLevel == 0 && StopAtNewline) return 0; if (!InString && (k == EndParen || k == BeginParen)) { if (forward == (k == BeginParen))/* Push a paren */ parenstack[ParenLevel++] = s -> s_table[c].MatchingParen; else { /* Pop a paren */ if (ParenLevel == 0) on_on = 0; /* Should maybe be error? */ else { if (parenstack[--ParenLevel] != c) error ("Parenthesis mismatch."); if (ParenLevel == 0 && !StopAtNewline) on_on = 0; } } } advance: if (!forward) { DotLeft (delta); delta = 1; } } MLvalue -> exp_int = 1; return 0; } ----------------------------------------------------------------------- Now, the diff listing, not including ParenScan: ----------------------------------------------------------------------- RCS file: RCS/syntax.c,v retrieving revision 1.1 diff -b -c -r1.1 syntax.c *** /tmp/,RCSt1005994 Mon Dec 19 05:10:26 1983 --- syntax.c Mon Dec 19 04:58:56 1983 *************** *** 13,14 static ! char *SyntaxTableNames[MaxSyntaxTables]; --- 13,14 ----- static ! char *SyntaxTableNames[MaxSyntaxTables + 1]; *************** *** 231,236 char c; ! p = locate (getnbstr (": dump-syntax-table ")); ! if (p == 0) return 0; SetBfn ("Syntax table"); --- 266,272 ----- char c; ! i = getword (SyntaxTableNames, ": dump-syntax-table "); ! if (i < 0) return 0; + p = SyntaxTables[i]; SetBfn ("Syntax table");