1 #LyX 1.4.0cvs created this file. For more info see http://www.lyx.org/
5 \textclass literate-article
10 \usepackage[ps2pdf,pdftitle={LyX listerrors re-implemented},urlcolor=blue,linktocpage,letterpaper,colorlinks=true]{hyperref}
11 \@savsf=1% This is to get around a hyperref+noweb interaction problem
15 % This (from the noweb FAQ) relaxes the constraint that chunks are never broken across pages.
17 \def\nwendcode{\endtrivlist \endgroup \vfil\penalty10\vfilneg}
18 \let\nwdocspar=\smallbreak
24 \paperfontsize default
31 \paperorientation portrait
34 \paragraph_separation indent
36 \quotes_language english
40 \paperpagestyle default
41 \tracking_changes false
60 \begin_inset LatexCommand \url{mailto:kayvan@sylvan.com}
72 \begin_layout Abstract
74 The listerrors program used to be compiled as a C program and installed
79 along with LyX in order to perform some simple re-formatting of noweb and
81 This document describes and implements the Python version of the same program.
84 \begin_layout Standard
87 \begin_inset LatexCommand \tableofcontents{}
99 \begin_layout Standard
101 The motivation for this program was Bugzilla bug 190
105 \begin_layout Standard
108 \begin_inset LatexCommand \url{http://bugzilla.lyx.org/show_bug.cgi?id=190}
118 \begin_inset Quotes eld
122 \begin_inset Quotes erd
128 \begin_layout Standard
131 \begin_inset Quotes eld
135 \begin_inset Quotes erd
138 ? Usually, LyX has great support for parsing of error messages.
139 For each error in the log file, LyX pops up an error box at that location
141 The error scanning routines expect these errors to be in a certain format
142 (similar to LaTeX errors).
143 When dealing with Literate Programs, you have
144 \begin_inset Quotes eld
151 \begin_layout Standard
154 \begin_inset LatexCommand \url{http://www.eecs.harvard.edu/~nr/noweb}
158 for more information about noweb.
164 \begin_inset Quotes erd
167 as well as gcc error messages (and potentially others).
168 The listerrors program attempts to standardize these error messages to
169 a format that LyX can parse and react to.
172 \begin_layout Standard
174 In a nutshell, the problems with the old implementation of listerrors that
175 bug 190 refers to were::
178 \begin_layout Enumerate
180 It was a C program and it was installed in the user path in the same directory
182 Having such a generically named binary in, for example,
186 , was potentially confusing.
189 \begin_layout Enumerate
191 It required that noweb be installed on the compiling machine (the source
192 was extracted by noweb from
194 SRCDIR/examples/Literate.lyx
196 , compiled and installed by
197 \begin_inset Quotes eld
201 \begin_inset Quotes erd
207 \begin_layout Standard
209 The new version deals with these problems in the following fashion:
212 \begin_layout Enumerate
214 Both the example file (this document) and the program are to be added to
215 the LyX CVS repository.
218 \begin_layout Enumerate
220 The program itself will be installed in
224 , along with other LyX-specific helper scripts.
227 \begin_layout Standard
229 In the design and implementation of this new
230 \begin_inset Quotes eld
234 \begin_inset Quotes erd
241 \begin_layout Standard
243 See the Python home page (
244 \begin_inset LatexCommand \url{http://www.python.org}
248 ) for more information.
253 language was chosen since it is fully multi-platform and provides a very
254 uniform and easy to read syntax.
255 This re-write also simplifies the code for
256 \begin_inset Quotes eld
260 \begin_inset Quotes erd
264 Python is installed by default on all modern Linux systems and is freely
265 available for all other platforms.
274 """reformat noweb and compiler errors for LyX.
278 Expects to read from stdin and output to stdout.
284 __author__ = "Kayvan A.
285 Sylvan <kayvan@sylvan.com>"
287 __date__ = "$Date: 2005/07/18 09:42:26 $"
289 __version__ = "$Revision: 1.5 $"
291 __credits__ = """Edmar Wienskoski Jr.
292 <edmar-w-jr@technologist.com>
294 original Literate support for LyX.
296 Bernard Michael Hurley <berhardh@westherts.ac.uk>
298 modifications to original listerrors."""
300 __copyright__ = "Copyright 2002 - Kayvan Sylvan."
312 if __name__ == "__main__":
319 \begin_layout Section
321 LaTeX style error message
324 \begin_layout Standard
326 The following function mimics the TeX error message format.
333 def write_error(msg, tool = "noweb", line_number = 1):
335 """Write out the given message in TeX error style.
339 called like: write_error(msg, tool, line_number)."""
341 print "! Build Error: ==> %s ==>
353 if type(msg) == type("str"): # simple string
357 else: # some kind of list (sequence or tuple)
370 \begin_layout Section
375 \begin_layout Standard
377 The only complication in our filtering code is that some parsers might need
378 to push back lines that are read in to be read again later.
379 We solve this problem by implementing a
380 \begin_inset Quotes eld
384 \begin_inset Quotes erd
388 \begin_inset Quotes eld
392 \begin_inset Quotes erd
402 __lines = [] # lines pushed back
406 def getline(file = sys.stdin):
408 """read a line from internal stack or from file.
412 optional file argument defaults to sys.stdin."""
424 line = file.readline()
433 \begin_layout Standard
435 And now for the corresponding pushline function:
444 "push a line onto the pushback stack."
457 \begin_layout Standard
459 The main() entry point function is extremely simple.
460 Note that this version of
461 \begin_inset Quotes eld
465 \begin_inset Quotes erd
468 takes no options and simply filters, attempting simply to match against
469 the known error message patterns.
470 The listerrors C program handled a single-character command-line argument
471 that the current code no longer needs.
481 """Entry point for listerrors.
486 Reads stdin and writes to stdout.
497 <<Check line against patterns and take action>>
502 \begin_layout Standard
504 For each line read in, we need to find out if it matches any of our tools
505 (noweb, gcc, etc.) and act accordingly.
510 <<Check line against patterns and take action>>=
512 try_patterns_dispatch = [ noweb_try, gcc_try, xlc_try ]
514 for predicate in try_patterns_dispatch:
516 if predicate(line): break
521 \begin_layout Section
523 Different Error Formats
526 \begin_layout Standard
528 The following sections handle the various error message formats that we
529 recognize in this program.
533 \begin_layout Subsection
538 \begin_layout Standard
540 Noweb errors are output on a single line, so examining just the current
550 """see if line is a noweb error.
554 Returns 1 on success, 0 otherwise.
555 Outputs on stdout."""
559 <<Look for the unescaped angle-brackets in documentation>>
561 <<Look for anything with double angle brackets>>
563 <<Last ditch effort scan for specific strings>>
572 \begin_layout Standard
574 First, we look for the
575 \begin_inset Quotes eld
578 unescaped < < in documentation chunk
579 \begin_inset Quotes erd
583 This is the only message with an associated line number from noweb.
588 <<Look for the unescaped angle-brackets in documentation>>=
590 if string.find(line, ": unescaped << in documentation chunk") != -1:
592 line_parts = string.split(line, ':')
594 num_str = line_parts[1]
596 num_len = len(num_str)
600 while i < num_len and (num_str[i] in string.digits): i = i + 1
604 write_error(":" + line_parts[2], "noweb", int(num_str))
611 \begin_layout Standard
613 Some noweb messages are simply about undefined scraps.
614 These can be seen by looking for matching double-angle-brackets.
619 <<Look for anything with double angle brackets>>=
623 left = string.find(line, "<<")
625 if (left != -1) and ((left + 2) < len(line)) and
629 (string.find(line[left+2:], ">>") != -1):
631 write_error(line, "noweb");
638 \begin_layout Standard
640 Finally, here is an additional list of explicit strings to check for.
645 <<Last ditch effort scan for specific strings>>=
649 msgs_to_try = ("couldn't open file",
651 "couldn't open temporary file",
653 "error writing temporary file",
659 "Bad format sequence",
661 "Can't open output file",
663 "Can't open temporary file",
665 "Capacity exceeded:",
667 "Ignoring unknown option -",
669 "This can't happen:",
671 "non-numeric line number in")
673 for msg in msgs_to_try:
675 if string.find(line, msg) != -1:
677 write_error(line, "noweb")
686 \begin_layout Subsection
691 \begin_layout Standard
693 The gcc errors can be multi-line, with the following format:
696 \begin_layout LyX-Code
698 foo.c: In function `main':
700 foo.c:3: `bar' undeclared (first use in this function)
702 foo.c:3: (Each undeclared identifier is reported only once
704 foo.c:3: for each function it appears in.)
706 foo.c:3: parse error before `x'
709 \begin_layout Standard
711 In order to parse this, the gcc error handler has to look ahead and return
712 any and all lines that do not match the expected pattern.
721 """See if line is a gcc error.
722 Read ahead to handle all the lines.
726 Returns 1 on success, 0 otherwise.
727 Outputs on stdout."""
731 <<Handle the gcc error message>>
740 \begin_layout Standard
742 The error message starts with a gcc header (as above) without an associated
748 <<Handle the gcc error message>>=
750 first_space = string.find(line, ' ')
752 if first_space > 1: # The smallest would be "X: "
754 if line[first_space - 1] == ':':
756 header_to_see = line[:first_space - 1]
758 next_line = getline()
760 if next_line and next_line[:first_space - 1] == header_to_see:
762 num_end = first_space
764 while next_line[num_end] in string.digits: num_end = num_end + 1
766 if num_end > first_space: # good!
768 <<Accumulate gcc error lines and print it>>
770 else: # oops! Not a gcc error.
776 pushline(next_line) # return this line to input stream
781 \begin_layout Standard
783 At the point in the code that we know that we are in the middle of an error
784 message, we do the following:
789 <<Accumulate gcc error lines and print it>>=
791 num_str = next_line[first_space:num_end]
793 msgs = [line[first_space:]]
795 msgs.append(next_line[num_end + 1:])
797 header_to_see = next_line[:num_end]
799 next_line = getline()
801 while next_line and next_line[:num_end] == header_to_see:
803 msgs.append(next_line[num_end + 1:])
805 next_line = getline()
807 if next_line: pushline(next_line)
809 write_error(msgs, "gcc", int(num_str))
816 \begin_layout Subsection
821 \begin_layout Standard
823 A xlc error message is easy to identify.
824 Every error message starts with a quoted string with no spaces, a comma,
826 \begin_inset Quotes eld
830 \begin_inset Quotes erd
833 , a space, and some variable text.
834 The following routine tests if a given buffer line matches this criteria
835 (this code would probably be simpler if I used the
836 \begin_inset Quotes eld
840 \begin_inset Quotes erd
843 regexp module, but we don't really need the full regular expression engine
854 """see if line is an xlc error.
858 Returns 1 on success, 0 otherwise.
859 Outputs on stdout."""
863 if line[0] == '"': # This is the first character of all xlc errors
865 next_quote = string.find(line, '"', 1)
867 first_space = string.find(line, ' ')
869 if (next_quote != -1) and (first_space > next_quote): # no space inisde
872 if line[first_space - 1:first_space + 6] == ", line ":
874 num_start = num_end = first_space + 6
876 while line[num_end] in string.digits: num_end = num_end + 1
878 if num_end > num_start:
880 write_error(line, "xlc", int(line[num_start : num_end]))
891 \begin_layout Section
896 \begin_layout Standard
898 This project can be tangled from LyX if you set your
899 \begin_inset Quotes eld
903 \begin_inset Quotes erd
906 convertor to call a generic script that always extracts a scrap named
911 Here is an example of such a generic script:
914 \begin_layout LyX-Code
918 notangle -Rbuild-script $1 | env NOWEB_SOURCE=$1 sh
921 \begin_layout Standard
923 This section defines our build-script, which extracts the code.
932 if [ -z "$NOWEB_SOURCE" ]; then NOWEB_SOURCE=listerrors.nw; fi
934 notangle -Rlisterrors ${NOWEB_SOURCE} > listerrors
941 \begin_layout Section
946 \begin_layout Standard
948 This section provides cross-references into the rest of the program.
951 \begin_layout Subsection
956 \begin_layout Standard
962 \begin_layout Standard
973 \begin_layout Subsection
978 \begin_layout Standard
984 \begin_layout Standard