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");