[net.emacs] Fix to backward paren bug wanted.

dragon@uw-june (Brian Matthews) (01/10/85)

In Raymond Dunn's C+ package (an excellent package, by the way), there
is a variable you can set indicating whether you have the fix to the
backward-paren bug (parentheses in comments are not ignored, and \\ and
single quotes screw things up).  Now, having this variable in there
seems to imply there is in fact such a fix out there, so I was
wondering if anyone has it.

Thanx,
Brian Matthews
dragon@uw-june

michael@spar.UUCP (michael) (01/11/85)

In response to Brian Matthew's request, I have enclosed the output
from `diff -c' -- syntax.c is the source file to be updated.

I can no longer remember who originally provided this fix, but
whoever it was has been a frequent contributor to this group.

Somewhere in here (I think..) is an additional fix I made that you'll really
want if you run Gosmacs on SUNs. SUN's C compiler has problems with
register variables (doesn't everybody's?) that show up here..

Oh yes, many thanks to the originator of this fix!

diff -c Oldsyntax.c syntax.c
*** Original Unipress EMACS syntax.c
--- With paren match correction
***************
*** 116,126
  
  /* 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  */
! /* Bugs: doesn't correctly handle comments (it'll never really handle them
!    correctly... */
! 
  static
          ParenScan (StopAtNewline, forward) {
      register    ParenLevel = 0;

--- 116,125 -----
  
  /* 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;
***************
*** 122,134
     correctly... */
  
  static
!         ParenScan (StopAtNewline, forward) {
!     register    ParenLevel = 0;
!     register char   c,
!                     pc;
!     char    parenstack[200];
!     int     InString = 0;
!     char    MatchingQuote = 0;
      register struct SyntaxTable *s = bf_mode.md_syntax;
      register    enum SyntaxKinds k;
      register    on_on = 1;

--- 121,127 -----
  /* 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,
***************
*** 131,139
      char    MatchingQuote = 0;
      register struct SyntaxTable *s = bf_mode.md_syntax;
      register    enum SyntaxKinds k;
!     register    on_on = 1;
!     int     start = (forward ? (dot + 1) : dot);
!     int     SavedDot = dot;
  
      parenstack[0] = 0;
      MLvalue -> exp_type = IsInteger;

--- 124,138 -----
  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;
***************
*** 135,141
      int     start = (forward ? (dot + 1) : dot);
      int     SavedDot = dot;
  
-     parenstack[0] = 0;
      MLvalue -> exp_type = IsInteger;
      MLvalue -> exp_int = 0;
      if (StopAtNewline) {

--- 134,139 -----
              MatchingQuote,
              delta = 1;
  
      MLvalue -> exp_type = IsInteger;
      MLvalue -> exp_int = 0;
      if (forward != 0 && forward != 1) {
***************
*** 138,153
      parenstack[0] = 0;
      MLvalue -> exp_type = IsInteger;
      MLvalue -> exp_int = 0;
!     if (StopAtNewline) {
! 	register    p1,
! 	            p2,
! 	            dp;
! 	for (p1 = dot - 1, p2 = (forward ? NumCharacters : FirstCharacter),
! 		dp = (forward ? 1 : -1);
! 		(forward ? p1 < p2 : p1 > p2)
! 		&& ((c = CharAt (p1)) == ' ' || c == '\t' || c == '\n');
! 		p1 += dp);
! 	SetDot (p1 + 1);
      }
      while (on_on && !err) {
  	if (forward) {

--- 136,144 -----
  
      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;
***************
*** 149,154
  		p1 += dp);
  	SetDot (p1 + 1);
      }
      while (on_on && !err) {
  	if (forward) {
  	    if (dot > NumCharacters) {

--- 140,162 -----
  	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)
***************
*** 151,159
      }
      while (on_on && !err) {
  	if (forward) {
! 	    if (dot > NumCharacters) {
! 		error ("No matching close parenthesis.");
! 		SetDot (SavedDot);
  		return 0;
  	    }
  	    DotRight (1);

--- 159,165 -----
   /* Scan through buffer until done or error */
      while (on_on && !err) {
  	if (forward) {
! 	    if (dot > NumCharacters)
  		return 0;
  	    DotRight (delta);
  	    delta = 1;
***************
*** 155,162
  		error ("No matching close parenthesis.");
  		SetDot (SavedDot);
  		return 0;
! 	    }
! 	    DotRight (1);
  	}
  	if (dot > 2)
  	    pc = CharAt (dot - 2);

--- 161,168 -----
  	if (forward) {
  	    if (dot > NumCharacters)
  		return 0;
! 	    DotRight (delta);
! 	    delta = 1;
  	}
  	else
  	    if (dot <= FirstCharacter)
***************
*** 158,170
  	    }
  	    DotRight (1);
  	}
! 	if (dot > 2)
! 	    pc = CharAt (dot - 2);
! 	else {
! 	    pc = 0;
! 	    if (dot <= FirstCharacter) {
! 		error ("No matching open parenthesis.");
! 		SetDot (SavedDot);
  		return 0;
  	    }
  	}

--- 164,171 -----
  	    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
***************
*** 166,171
  		error ("No matching open parenthesis.");
  		SetDot (SavedDot);
  		return 0;
  	    }
  	}
  	k = bf_mode.md_syntax -> s_table[c = CharAt (dot - 1)].s_kind;

--- 167,185 -----
  	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)
***************
*** 167,172
  		SetDot (SavedDot);
  		return 0;
  	    }
  	}
  	k = bf_mode.md_syntax -> s_table[c = CharAt (dot - 1)].s_kind;
  	if (bf_mode.md_syntax -> s_table[pc].s_kind == PrefixQuote)

--- 181,192 -----
  		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)
***************
*** 168,179
  		return 0;
  	    }
  	}
! 	k = bf_mode.md_syntax -> s_table[c = CharAt (dot - 1)].s_kind;
! 	if (bf_mode.md_syntax -> s_table[pc].s_kind == PrefixQuote)
! 	    k = WordChar;
! 	if ((!InString || c == MatchingQuote) && k == PairedQuote) {
! 	    InString = !InString;
! 	    MatchingQuote = c;
  	}
  	if (InString && c == '\n')
  	    return 0;

--- 188,209 -----
  		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;
***************
*** 175,181
  	    InString = !InString;
  	    MatchingQuote = c;
  	}
! 	if (InString && c == '\n')
  	    return 0;
  	if (StopAtNewline && c == '\n' && ParenLevel == 0)
  	    return 0;

--- 205,211 -----
  		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 */
***************
*** 177,184
  	}
  	if (InString && c == '\n')
  	    return 0;
- 	if (StopAtNewline && c == '\n' && ParenLevel == 0)
- 	    return 0;
  	if (!InString && (k == EndParen || k == BeginParen)) {
  	    if ((forward == 0) == (k == EndParen)) {
  		ParenLevel++;

--- 207,212 -----
  	}
  	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;
***************
*** 180,188
  	if (StopAtNewline && c == '\n' && ParenLevel == 0)
  	    return 0;
  	if (!InString && (k == EndParen || k == BeginParen)) {
! 	    if ((forward == 0) == (k == EndParen)) {
! 		ParenLevel++;
! 		parenstack[ParenLevel] = s -> s_table[c].MatchingParen;
  	    }
  	    else {
  		if (ParenLevel > 0 && parenstack[ParenLevel] != c)

--- 208,224 -----
  	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: 
***************
*** 184,200
  		ParenLevel++;
  		parenstack[ParenLevel] = s -> s_table[c].MatchingParen;
  	    }
- 	    else {
- 		if (ParenLevel > 0 && parenstack[ParenLevel] != c)
- 		    error ("Parenthesis mismatch.");
- 		ParenLevel--;
- 	    }
- /*	    if (pc == '\n' && ParenLevel > 0 && dot != start) {
- 		error ("Parenthesis context across function boundary");
- 		return 0;
- 	    } */
- 	    if (ParenLevel < 0 || (ParenLevel == 0 && !StopAtNewline))
- 		on_on = 0;
  	}
  	if (!forward)
  	    DotLeft (1);

--- 220,225 -----
  			on_on = 0;
  		}
  	    }
  	}
  advance: 
  	if (!forward) {
***************
*** 196,203
  	    if (ParenLevel < 0 || (ParenLevel == 0 && !StopAtNewline))
  		on_on = 0;
  	}
! 	if (!forward)
! 	    DotLeft (1);
      }
      MLvalue -> exp_int = 1;
      return 0;

--- 221,231 -----
  		}
  	    }
  	}
! advance: 
! 	if (!forward) {
! 	    DotLeft (delta);
! 	    delta = 1;
! 	}
      }
      MLvalue -> exp_int = 1;
      return 0;
=======END OF DIFF=======

-michael

chris@umcp-cs.UUCP (Chris Torek) (01/12/85)

Re: getting Gosling Emacs to match parens in, e.g., ("hi("'\\' /* { */):
I have such a fix; I even recall sending it out.  UniPress has the fix
now too, so maybe it will appear in later versions of the commercial
Emacs.

I don't have the original code anymore, so the best I could do now is
post just the paren matcher code, and let others figure out where it
goes.  (In other words, I can't send out diff listings.)
-- 
(This line accidently left nonblank.)

In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7690)
UUCP:	{seismo,allegra,brl-bmd}!umcp-cs!chris
CSNet:	chris@umcp-cs		ARPA:	chris@maryland