As a student of Faculty of mathematics I usually write long (La)TeX documents involving lots of braces, of various kinds. So I wrote this script:
#!/usr/bin/perl if ( $#ARGV==-1 ) { die "Not enough arguments"; } open IN, "<".$ARGV[0] or die "Cannot open `$ARGV[0]'"; $brc[0]=$brc[1]=$brc[2]=0; while (<IN>) { while (( s/\\\(// || (s/\(// && ($brc[0]++, print "(")) ) || ( s/\\\)// || (s/\)// && ($brc[0]--, print ")")) ) || ( s/\\\{// || (s/\{// && ($brc[1]++, print "{")) ) || ( s/\\\}// || (s/\}// && ($brc[1]--, print "}")) ) || ( s/\\\[// || (s/\[// && ($brc[2]++, print "[")) ) || ( s/\\\]// || (s/\]// && ($brc[2]--, print "]")) )) { ; } } print "\n(): $brc[0], {}: $brc[1], []: $brc[2]\n";
It checks for unmatched pairs of braces, skipping the backslashed forms. At the end, if all three numbers aren't zero, then there are unmatched brace(s) somewhere in the document. That's it! It's small, effective, and it does its work!

Replies are listed 'Best First'.
Re: (La)TeX brace counter (athomason)
by athomason (Curate) on Jul 18, 2000 at 13:37 UTC
    Useful, certainly, but it seems to me you're defining "unmatched braces" as a mismatch in the count over the whole document of left and right versions of the brace types. By my definition, at least, the term is stronger than that: braces must also be properly nested (i.e. '({)}' is invalid). I'd be more inclined to do something like the following (a fairly simple stack model), which catches such errors and as a bonus gives more information about where the error occurred:
    #!/usr/bin/perl -w use strict; my %x = (')'=>'(','}'=>'{',']'=>'['); my @braces = (); while (<>) { s/\\(\(|\)|\{|\}|\[|\])//g; # yank out escaped braces for (split //, $_) { # split each line into chars push(@braces, $_), next if (/\(|\{|\[/); # push if left brace /(\)|\}|\])/ and # if right brace (@braces > 0 # and left braces on stack ? $braces[-1] eq $x{$1} # and right brace matches left ? pop @braces # pop the pair : (print("unmatched '$braces[-1]' before '$_' on line $."), e +xit) # saw a left without correct right : (print("no match for '$_' on line $."), exit) # saw a right + with no stack ); } } print "passed!\n";

    This is barely tested, so nobody go using it anywhere. Granted, this doesn't take quoted braces into account, but that's a whole different story.

      Yes, I am aware that there exist tools such as (k)LyX now, but as a regular (Perl & Linux) monk I type (La)TeX docs directly in Emacs... ;^) You were right, I didn't mention that what my script REALLY does is just to COUNT braces, and not to take care of their order, so this was unclear. But I suppose every decent brother out there understood my code... or am I wrong??! Anyway, TNX! ;^))