├── README.md ├── ebnf.sno ├── groff-mom.outlang ├── groff-ms.outlang ├── groff.nanorc ├── highlight.lua ├── highlight.sno ├── htbl.tes ├── plantuml.cfg ├── pygments-groff.py ├── samples ├── select-from.ebnf └── select-from.ps ├── sql.lang ├── syntax.pic ├── uml-graph └── sequence.pic └── uml.sno /README.md: -------------------------------------------------------------------------------- 1 | # Groff Preprocessors and Tools 2 | 3 | This repository is home to an assortment of preprocessors and 4 | macros for the [GNU Troff](http://www.gnu.org/software/groff/) typesetting 5 | package. 6 | 7 | I have written all of them except `sequence.pic` which is part of the 8 | [UML Graph](http://www.umlgraph.org/) package and included here for convenience 9 | only. 10 | These scripts do not strive to be complete, well tested and fit for general usage - they 11 | are merely quick and dirty hacks that accumulated on my hard drive :-). 12 | 13 | ## EBNF 14 | 15 | `ebnf.sno` is a [CSNOBOL4](http://www.regressive.org/snobol4/csnobol4/) program that compiles 16 | extended BNF descriptions into GNU pic code using macros from `syntax.pic`. 17 | This effectively allows you to embed EBNF grammars in Groff source code and 18 | have it rendered as (box and arrow) syntax diagrams. 19 | Most EBNF constructs and some extensions are supported, but I'm too lazy to document 20 | all of them now. 21 | 22 | To build the sample `select-from.ebnf`, type something like: 23 | 24 | cat samples/select-from.ebnf | ./ebnf.sno | pic | groff -Tps >select-from.ps 25 | 26 | ## HIGHLIGHT (Python) 27 | 28 | `pygments-groff.py` is a syntax highlighting preprocessor based on [Pygments](https://pygments.org/) and 29 | consequently written in Python 3. 30 | It is the most powerful (and probably fastest) of the syntax highlighting preprocessors presented here. 31 | It should also be more portable as it does not rely on stdout redirection magic. 32 | It should work with all Groff macro suites and even preserves the line numbering 33 | in Groff error messages. 34 | 35 | You can process embedded blocks of code as in the following ms-based example: 36 | 37 | ```groff 38 | .LD 39 | .CW 40 | .lg 0 41 | .HIGHLIGHT c 42 | #include 43 | 44 | int main(int argc, char **argv) 45 | { 46 | printf("Hello world!\n"); 47 | return 0; 48 | } 49 | .HIGHLIGHT 50 | .DE 51 | ``` 52 | 53 | Note that you may have to do more before `.HIGHLIGHT` - for instance redefine chars - 54 | depending on your use case. 55 | 56 | The `default` language identifier is useful to include code without highlighting, 57 | but still benefit from Pygment's preprocessing in order to achieve verbatim text. 58 | A list of language identifiers (short names) can be found on the [Pygments website](https://pygments.org/languages/). 59 | 60 | Just like `highlight.lua`, you can specify a file name directly after the language identifier: 61 | 62 | ```groff 63 | .HIGHLIGHT c hello.c 64 | ``` 65 | 66 | ## HIGHLIGHT (SNOBOL4) 67 | 68 | `highlight.sno` is a small preprocessor written in [CSNOBOL4](http://www.regressive.org/snobol4/csnobol4/) 69 | that processes blocks of source code embedded in your Groff document with 70 | [GNU Source-highlight](http://www.gnu.org/software/src-highlite/) to produce 71 | syntax highlighted text. 72 | 73 | The output is formatted according to `groff.outlang`. 74 | Versions for the [mom macros](http://www.schaffter.ca/mom/) (`groff-mom.outlang`) and 75 | for the classic ms macros (`groff-ms.outlang`) are provided. 76 | 77 | Example (mom): 78 | 79 | ```groff 80 | .QUOTE 81 | .CODE 82 | .HIGHLIGHT c 83 | #include 84 | 85 | int main(int argc, char **argv) 86 | { 87 | printf("Hello world!\n"); 88 | return 0; 89 | } 90 | .HIGHLIGHT 91 | .CODE OFF 92 | .QUOTE OFF 93 | ``` 94 | 95 | ## HIGHLIGHT (Lua) 96 | 97 | `highlight.lua` is a reimplementation of `highlight.sno` in Lua 5.2 and may work 98 | better on some operating systems. 99 | 100 | In addition to the aforementioned syntax, the Lua version allows you to specify a filename after 101 | the language identifier to process an external file: 102 | 103 | ```groff 104 | .HIGHLIGHT c hello.c 105 | ``` 106 | 107 | ## UML 108 | 109 | `uml.sno` is a small preprocessor (again requires CSNOBOL4) that 110 | renders an embedded diagram with [PlantUML](http://plantuml.sourceforge.net/) 111 | and automatically emits the appropriate Mom `PDF_IMAGE` macro calls. 112 | 113 | Naturally, this leaves around PDF images (`uml_tempX.pdf`) that you should remove 114 | after generating your document. 115 | 116 | ## HTML Tables 117 | 118 | `htbl.tes` is a quick and dirty [SciTECO](http://rhaberkorn.github.com/sciteco/) script 119 | that can act as a drop-in replacement for the tbl preprocessor that generates 120 | proper HTML tables when the Groff html output device is used. 121 | With the original tbl preprocessor, tables are (and must be) rendered by the postscript 122 | device and will be embedded as images into the HTML page. 123 | -------------------------------------------------------------------------------- /ebnf.sno: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/snobol4 -b 2 | 3 | *** 4 | *** Definitions 5 | *** 6 | define('optspace(pattern)') 7 | define('string()') 8 | define('serialize()') 9 | strings = array(2) 10 | str_no = 0 11 | 12 | define('emit_groff(str)') 13 | 14 | define('begin_rule()') 15 | define('end_rule()') 16 | 17 | define('emit_nonterm()') 18 | define('emit_term()') 19 | define('emit_empty()') 20 | 21 | define('begin_exp()') 22 | define('end_exp()') 23 | 24 | define('begin_alt()') 25 | define('end_alt()') 26 | define('repeat()') 27 | define('repeat_with()') 28 | 29 | &anchor = 1 30 | &fullscan = 1 31 | 32 | *** 33 | *** EBNF grammar 34 | *** 35 | letter = &lcase &ucase 36 | digit = "0123456789" 37 | 38 | space = span(" " char(9) char(10) char(13)) | "" 39 | eol = break(char(10) char(13)) 40 | nonterm = ( "`" break("`") $ *string() "`" 41 | + | (any(letter) (span(letter digit "_") | "")) $ *string() ) 42 | + (optspace("~") *nonterm | "") 43 | term = ( "'" break("'") $ *string() "'" 44 | + | '"' break('"') $ *string() '"' ) 45 | + (optspace("~") *term | "") 46 | 47 | lhs = nonterm 48 | exp = nonterm *emit_nonterm() 49 | + | term *emit_term() 50 | + | optspace("[") *emit_empty() *begin_alt() *rhs optspace("]") *end_alt() 51 | + | optspace("{") *begin_exp() *rhs optspace("}") *end_exp() 52 | + (optspace("~") term *repeat_with() | *repeat()) 53 | + | optspace("(") *begin_exp() *rhs optspace(")") *end_exp() 54 | + | *emit_empty() 55 | rhs = exp 56 | + ( optspace("|") *begin_alt() *rhs *end_alt() 57 | + | optspace(",") *rhs 58 | + | "") 59 | 60 | * NOTE: have to reset str_no if there is no lhs, since 61 | * strings may already contain a nonterminal 62 | rule = ( lhs optspace("=" | ":=" | "::=") 63 | + | *?(str_no = 0) "" $ *string() ) 64 | + *begin_rule() rhs optspace(";") *end_rule() 65 | comment = optspace("(*" breakx("*") "*)" | "#" eol) 66 | groff = optspace("." eol $ str) *emit_groff(str) 67 | pic = optspace("%" eol $ output) 68 | grammar = arbno(comment | groff | pic | rule) rpos(0) 69 | 70 | *** 71 | *** MAIN 72 | *** 73 | lineno = 1 74 | 75 | loop line = input :f(end) 76 | line ".lf " int . lineno :s(next) 77 | line ".EBNF" :s(src.l) 78 | lineno = lineno + 1 79 | next output = line :(loop) 80 | 81 | src.l line = input 82 | lineno = lineno + 1 83 | line ".EBNF" :s(compile) 84 | src = src line char(10) :(src.l) 85 | 86 | compile 87 | output = ".PS" 88 | output = 'copy "syntax.pic";' 89 | (src ? grammar, terminal = "FAILURE") 90 | output = 'reset;' 91 | output = ".PE" 92 | output = ".lf " (lineno + 1) 93 | src = "" :(loop) 94 | 95 | *** 96 | *** Procedures 97 | *** 98 | optspace 99 | optspace = space pattern space :(return) 100 | 101 | string 102 | string = .strings[str_no = str_no + 1] :(nreturn) 103 | serialize 104 | * NOTE: will leave str_no == 0 105 | serialize = '"' strings[str_no] '" ' serialize 106 | eq(str_no = str_no - 1, 0) :s(return)f(serialize) 107 | 108 | emit_groff 109 | output = 'command ".' str '";' :(return) 110 | 111 | begin_rule 112 | output = 'begin_rule(' serialize() ');' :(return) 113 | end_rule 114 | output = 'end_rule();' :(return) 115 | 116 | emit_nonterm 117 | output = 'nonterminal(' serialize() ');' :(return) 118 | emit_term 119 | output = 'terminal(' serialize() ');' :(return) 120 | emit_empty 121 | output = 'empty();' :(return) 122 | 123 | begin_exp 124 | output = 'begin_group();' :(return) 125 | end_exp 126 | output = 'end_group();' :(return) 127 | 128 | begin_alt 129 | output = 'begin_alt(last []);' :(return) 130 | end_alt 131 | output = 'end_alt(2nd last []);' :(return) 132 | 133 | repeat output = 'repeat(last []);' :(return) 134 | repeat_with 135 | output = 'repeat_with(last [],' serialize() ');' :(return) 136 | 137 | end 138 | 139 | -------------------------------------------------------------------------------- /groff-mom.outlang: -------------------------------------------------------------------------------- 1 | extension "mom" 2 | 3 | doctemplate 4 | " 5 | .NEWCOLOR green RGB #33CC00 6 | .NEWCOLOR red RGB #FF0000 7 | .NEWCOLOR darkred RGB #990000 8 | .NEWCOLOR blue RGB #0000FF 9 | .NEWCOLOR brown RGB #9A1900 10 | .NEWCOLOR pink RGB #CC33CC 11 | .NEWCOLOR yellow RGB #FFCC00 12 | .NEWCOLOR cyan RGB #66FFFF 13 | .NEWCOLOR purple RGB #993399 14 | .NEWCOLOR orange RGB #FF6600 15 | .NEWCOLOR brightorange RGB #FF9900 16 | .NEWCOLOR brightgreen RGB #33FF33 17 | .NEWCOLOR darkgreen RGB #009900 18 | .NEWCOLOR black RGB #000000 19 | .NEWCOLOR teal RGB #008080 20 | .NEWCOLOR gray RGB #808080 21 | .NEWCOLOR darkblue RGB #000080 22 | .NEWCOLOR white RGB #FFFFFF 23 | " 24 | 25 | " 26 | " 27 | end 28 | 29 | # NOTE: There must be a Typewrite Bold style 30 | # I'm using the Latin Modern fonts that have this style. 31 | # Otherwise you could use Mom's \*[BOLDER] escape. 32 | 33 | bold "\f[TTB]$text\fP" 34 | italics "\f[TTI]$text\fP" 35 | # FIXME: no way to implement underline generically 36 | #underline 37 | 38 | #notfixed "\fR$text\fP" 39 | #fixed "\fR$text\fP" 40 | 41 | color "\*[$style]$text\*[black]" 42 | 43 | colormap 44 | "green" "green" 45 | "red" "red" 46 | "darkred" "darkred" 47 | "blue" "blue" 48 | "brown" "brown" 49 | "pink" "pink" 50 | "yellow" "yellow" 51 | "cyan" "cyan" 52 | "purple" "purple" 53 | "orange" "orange" 54 | "brightorange" "brightorange" 55 | "brightgreen" "brightgreen" 56 | "darkgreen" "darkgreen" 57 | "black" "black" 58 | "teal" "teal" 59 | "gray" "gray" 60 | "darkblue" "darkblue" 61 | "white" "white" 62 | default "black" 63 | end 64 | 65 | # lines may be empty, so begin them with the non-spacing \& 66 | # also, this allows "." and "'" at the beginning of the line 67 | lineprefix "\&" 68 | 69 | translations 70 | "\\" "\\e" 71 | #"\t" " " 72 | end 73 | -------------------------------------------------------------------------------- /groff-ms.outlang: -------------------------------------------------------------------------------- 1 | extension "ms" 2 | 3 | bold "\f[CB]$text\fP" 4 | italics "\f[CI]$text\fP" 5 | underline "\f[CI]$text\fP" 6 | fixed "\f[CR]$text\fP" 7 | color "\m[$style]$text\m[black]" 8 | 9 | #anchor "$infilename : $linenum - $text" 10 | #reference "$text \(-> $infile:$linenum, page : $infilename:$linenum" 11 | 12 | # lines may be empty, so begin them with the non-spacing \& 13 | # also, this allows "." and "'" at the beginning of the line 14 | lineprefix "\&" 15 | 16 | colormap 17 | "green" "green" 18 | "red" "red" 19 | "darkred" "darkred" 20 | "blue" "blue" 21 | "brown" "brown" 22 | "pink" "pink" 23 | "yellow" "yellow" 24 | "cyan" "cyan" 25 | "purple" "purple" 26 | "orange" "orange" 27 | "brightorange" "brightorange" 28 | "brightgreen" "brightgreen" 29 | "darkgreen" "darkgreen" 30 | "black" "black" 31 | "teal" "teal" 32 | "gray" "gray" 33 | "darkblue" "darkblue" 34 | default "black" 35 | end 36 | 37 | translations 38 | "\\" "\\e" 39 | #"\t" " " 40 | end 41 | -------------------------------------------------------------------------------- /groff.nanorc: -------------------------------------------------------------------------------- 1 | ## Here is an example for groff. 2 | ## 3 | syntax "groff" "(\.m[ems]|\.mom)$" "\.rof" "\.tmac$" "^tmac." 4 | ## The argument of .ds or .nr 5 | color cyan "^\.[[:space:]]*(ds|nr)[[:space:]]+[^[:space:]]*" 6 | ## Single character escapes 7 | color brightmagenta "\\." 8 | ## Highlight the argument of \f or \s in the same color 9 | color brightmagenta "\\f." "\\f\(.." "\\s(\+|\-)?[0-9]" 10 | ## Newlines 11 | color cyan "(\\|\\\\)n(.|\(..)" 12 | color cyan start="(\\|\\\\)n\[" end="]" 13 | ## Requests 14 | color brightgreen "^\.[[:space:]]*[^[:space:]]*" 15 | ## Comments 16 | color yellow "^\.\\".*$" 17 | color yellow "\\".*$" 18 | color yellow "^\\#.*$" 19 | ## Strings 20 | color green "(\\|\\\\)\*(.|\(..)" 21 | color green start="(\\|\\\\)\*\[" end="]" 22 | ## Characters 23 | color brightred "\\\(.." 24 | color brightred start="\\\[" end="]" 25 | ## Macro arguments 26 | color brightcyan "\\\\\$[1-9]" 27 | -------------------------------------------------------------------------------- /highlight.lua: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/lua52 2 | local pipe 3 | local line_prefix = '' 4 | 5 | for line in io.input():lines() do 6 | if pipe then 7 | if line:match("^%. *HIGHLIGHT *") then 8 | pipe:close() 9 | pipe = nil 10 | -- empty line to fix up line numbering 11 | -- FIXME: the linefeed is necessary because source-highlight did not 12 | -- terminate the last line 13 | print "\n." 14 | else 15 | -- the last linefeed is not piped, so that we don't get empty lines 16 | -- at the end of a code block 17 | pipe:write(line_prefix, line) 18 | line_prefix = '\n' 19 | end 20 | else 21 | local lang = line:match("^%. *HIGHLIGHT +(.*)$") 22 | if lang then 23 | if lang:match(" ") then 24 | local file 25 | lang, file = lang:match("^([^ ]*) +(.*)$") 26 | lang = lang == "default" and "--failsafe" or "-s "..lang 27 | os.execute("source-highlight --outlang-def groff.outlang "..lang.." -i "..file) 28 | -- FIXME: Emit .lf statement 29 | -- FIXME: Omit the last character 30 | print "" 31 | else 32 | lang = lang == "default" and "--failsafe" or "-s "..lang 33 | pipe = io.popen("source-highlight --outlang-def groff.outlang "..lang, "w") 34 | -- empty line to fix up line numbering 35 | print "." 36 | -- omit linefeed on first print 37 | line_prefix = '' 38 | end 39 | else 40 | print(line) 41 | end 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /highlight.sno: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/snobol4 -b 2 | 3 | &anchor = 1 4 | * flush OUTPUT immediately 5 | output(.output, 6, "W") 6 | 7 | loop line = input :f(end) 8 | line ".HIGHLIGHT " rem . language :s(pipe) 9 | output = line :(loop) 10 | 11 | * empty line to fixup line numbering 12 | pipe output = "." 13 | * FIXME: hack to strip the last byte (linefeed) since source-highlight 14 | * is picky about newlines at the end of the file (will print another lineprefix) 15 | output(.pipe, 100,, 16 | + "| head -c -1 | source-highlight --outlang-def groff.outlang -s " language) 17 | 18 | pipe_l line = input 19 | line ".HIGHLIGHT" :s(close) 20 | pipe = line :(pipe_l) 21 | 22 | close endfile(100) 23 | * empty line to fixup line numbering 24 | * FIXME: the linefeed is necessary because source-highlight did not terminate 25 | * the last line 26 | output = char(10) "." :(loop) 27 | 28 | end 29 | -------------------------------------------------------------------------------- /htbl.tes: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/sciteco -m 2 | !* htbl.tes *! 3 | !* Troff tbl "drop-in" replacement *! 4 | 5 | 0,2EJ !* FIXME: Memory limiting is too slow *! 6 | 7 | LR 0X#in 2LR 0X#ou EBN#in EB -EF 8 | 9 | < 10 | !* 11 | * will implicitly close

's so we must recalculate the margin. 12 | * we do this using the same formula as

indentions are calculated by post-grohtml 13 | * except for the line-length which is apparently always 6.5i (the default) 14 | *! 15 | FS.TS.nr tbl-margin ((\n[.in]+\n[.o])*100+(6.5i/2))/6.5i-((6.5i/2)/6.5i) 16 | .nr tbl-width 100-\n[tbl-margin] 17 | .HTML

 L 33 | 34 | 1u.[row] 1u.[col] 35 | @.r{ 36 | .[format.\.[row].\.[col].align] 0U.[format.\.[row].\.[col].bold] 0U.[format.\.[row].\.[col].italic] 37 | 1U.[format.\.[row].\.[col].rowspan] 1U.[format.\.[row].\.[col].colspan] 38 | 0U.[format.\.[row].hsep] 39 | } :M.r 40 | < 41 | 0a-L"=.[format.\.[row].\.[col].align]left' 42 | 0a-C"=.[format.\.[row].\.[col].align]center' 43 | 0a-R"=.[format.\.[row].\.[col].align]right' 44 | 0a-B"=1U.[format.\.[row].\.[col].bold]' 45 | 0a-I"=1U.[format.\.[row].\.[col].italic]' 46 | 0a- "=%.[col] :M.r' 47 | 0a-,"=%.[row] 1u.[col] :M.r' 0a-10"=%.[row] 1u.[col] :M.r' 48 | 0a-."=1;' 49 | D> 50 | 51 | k q.[row]u.[frows] q.[col]u.[fcols] 1u.[row] 1u.[col] .u.#bd 52 | < 53 | Q.[row]-Q.[frows]"> 54 | EU.[format.\.[row].\.[col].align]Q.[format.\.[frows].\.[col].align] 55 | Q.[format.\.[frows].\.[col].bold]U.[format.\.[row].\.[col].bold] 56 | Q.[format.\.[frows].\.[col].italic]U.[format.\.[row].\.[col].italic] 57 | Q.[format.\.[frows].\.[col].rowspan]U.[format.\.[row].\.[col].rowspan] 58 | Q.[format.\.[frows].\.[col].colspan]U.[format.\.[row].\.[col].colspan] 59 | :Q.[format.\.[row].hsep]"< 60 | 0U.[format.\.[row].hsep] 61 | ' 62 | ' 63 | 64 | .-1,.+2:S^J=^J"S 1U.[format.\.[row].hsep] ' 65 | 66 | .,.+3:ST{^J"S 67 | .,S^JT}.-3X.[data.\.[row].\.[col]] C 1 68 | | 69 | .,.+2:S\^^"S 70 | 0U.[format.\.[row].\.[col].rowspan] 71 | Q.[row]-1U.#cr 72 | 1;' -%.#cr> 73 | %.[format.\.#cr.\.[col].rowspan] 74 | ' 75 | .U.f S[U.[tab],^J] 76 | Q.f,.-1X.[data.\.[row].\.[col]] 0 77 | ' 78 | U.[data.\.[row].\.[col].block] 79 | -A-Q.[tab]"= 80 | %.[col] 81 | | 82 | %.[row] 1U.[col] .,.+4:S.TE^J"S1;' 83 | ' 84 | > 85 | q.#bd,.D 86 | 87 | q.[row]-1u.[drows] 1u.[row] 88 | q.[drows]< 89 | I.HTML ^J 90 | 1u.[col] 91 | q.[fcols]< 92 | Q.[format.\.[row].\.[col].rowspan]"> 93 | I.HTML ^J 103 | | 104 | I>^J 105 | G.[data.\.[row].\.[col]] 106 | I^J.HTML ^J 107 | ' 108 | ' 109 | %.[col]> 110 | I.HTML ^J 111 | %.[row]> 112 | I.HTML
 97 | Q.[format.\.[row].\.[col].bold]"N I ' 98 | Q.[format.\.[row].\.[col].italic]"N I ' 99 | G.[data.\.[row].\.[col]] 100 | Q.[format.\.[row].\.[col].bold]"N I ' 101 | Q.[format.\.[row].\.[col].italic]"N I ' 102 | I
^J 113 | > 114 | 115 | EWQ#ou 116 | EX -------------------------------------------------------------------------------- /plantuml.cfg: -------------------------------------------------------------------------------- 1 | ' CMU Serif is a TrueType Computer Modern Unicode font 2 | ' This results in additional fonts in the final PDF, but is much easier 3 | ' than trying to use the same fonts Groff uses 4 | skinparam defaultFontName CMU Serif 5 | skinparam defaultFontSize 9 6 | 7 | skinparam monochrome true 8 | 9 | skinparam shadowing false 10 | 11 | -------------------------------------------------------------------------------- /pygments-groff.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python3.9 2 | from pygments.lexers import get_lexer_by_name, RawTokenLexer 3 | from pygments.formatters import GroffFormatter 4 | from pygments import highlight 5 | import re 6 | from sys import stdin, stdout, stderr 7 | 8 | formatter = GroffFormatter(style="sas") 9 | 10 | start_pattern = re.compile(r"\. *HIGHLIGHT +([^ ]+)( +(.*))?\n") 11 | end_pattern = re.compile(r"\. *HIGHLIGHT *\n") 12 | 13 | while True: 14 | for line in stdin: 15 | stdout.write(line) 16 | params = start_pattern.match(line) 17 | if params: 18 | break 19 | if not params: # EOF 20 | break 21 | 22 | lang, filename = params.group(1, 3) 23 | 24 | lexer = RawTokenLexer() if lang == "default" else get_lexer_by_name(lang) 25 | # NOTE: This option is broken and will result in a bogus empty line with the GroffFormatter 26 | lexer.ensurenl = False 27 | 28 | contents = [] 29 | if filename: 30 | contents.append(open(filename).read()) 31 | stdout.write(".ds HIGHLIGHT-LF \\n[.c] \\n[.F]\n") 32 | stdout.write(".lf 1 "+filename+"\n") 33 | else: 34 | for line in stdin: 35 | if end_pattern.match(line): 36 | stdout.write(line) 37 | break 38 | contents.append(line) 39 | 40 | formatted = highlight("".join(contents), lexer, formatter) 41 | stdout.write(formatted.replace("\n\n", "\n\\&\n")+"\n") 42 | if filename: 43 | stdout.write(".lf \\*[HIGHLIGHT-LF]\n") 44 | -------------------------------------------------------------------------------- /samples/select-from.ebnf: -------------------------------------------------------------------------------- 1 | .EBNF 2 | ### 3 | ### SQL SELECT FROM statement 4 | ### 5 | 6 | %linewid = linewid/2; 7 | %boxwid = boxwid*1.3; 8 | %boxht = boxht*0.8; 9 | %circlerad = boxht/2; 10 | 11 | `\f[BI]SELECT\fP`~Statement = `\fBSELECT\fP`, ("*" | {Derived~Column}~","), 12 | Table; 13 | Derived~Column = Scalar~Expression, [`\fBAS\fP`, Column~Name]; 14 | 15 | Table = `\fBFROM\fP`, {Table~Name}~",", 16 | [`\f[BI]WHERE\fP`~Clause], 17 | [`\f[BI]GROUP BY\fP`~Clause], 18 | [`\f[BI]ORDER BY\fP`~Clause]; 19 | 20 | `\f[BI]WHERE\fP`~Clause = `\fBWHERE\fP`, Condition; 21 | 22 | `\f[BI]GROUP BY\fP`~Clause = `\fBGROUP\fP`, `\fBBY\fP`, 23 | {Column~Name}~","; 24 | 25 | `\f[BI]ORDER BY\fP`~Clause = `\fBORDER\fP`, `\fBBY\fP`, { 26 | Column~Name, 27 | [`\fBASCENDING\fP` | `\fBDESCENDING\fP`] 28 | }~","; 29 | .EBNF 30 | -------------------------------------------------------------------------------- /samples/select-from.ps: -------------------------------------------------------------------------------- 1 | %!PS-Adobe-3.0 2 | %%Creator: groff version 1.22.2 3 | %%CreationDate: Thu Dec 5 18:52:03 2013 4 | %%DocumentNeededResources: font Times-BoldItalic 5 | %%+ font Times-Roman 6 | %%+ font Times-Bold 7 | %%DocumentSuppliedResources: procset grops 1.22 2 8 | %%Pages: 1 9 | %%PageOrder: Ascend 10 | %%DocumentMedia: Default 612 792 0 () () 11 | %%Orientation: Portrait 12 | %%EndComments 13 | %%BeginDefaults 14 | %%PageMedia: Default 15 | %%EndDefaults 16 | %%BeginProlog 17 | %%BeginResource: procset grops 1.22 2 18 | %!PS-Adobe-3.0 Resource-ProcSet 19 | /setpacking where{ 20 | pop 21 | currentpacking 22 | true setpacking 23 | }if 24 | /grops 120 dict dup begin 25 | /SC 32 def 26 | /A/show load def 27 | /B{0 SC 3 -1 roll widthshow}bind def 28 | /C{0 exch ashow}bind def 29 | /D{0 exch 0 SC 5 2 roll awidthshow}bind def 30 | /E{0 rmoveto show}bind def 31 | /F{0 rmoveto 0 SC 3 -1 roll widthshow}bind def 32 | /G{0 rmoveto 0 exch ashow}bind def 33 | /H{0 rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def 34 | /I{0 exch rmoveto show}bind def 35 | /J{0 exch rmoveto 0 SC 3 -1 roll widthshow}bind def 36 | /K{0 exch rmoveto 0 exch ashow}bind def 37 | /L{0 exch rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def 38 | /M{rmoveto show}bind def 39 | /N{rmoveto 0 SC 3 -1 roll widthshow}bind def 40 | /O{rmoveto 0 exch ashow}bind def 41 | /P{rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def 42 | /Q{moveto show}bind def 43 | /R{moveto 0 SC 3 -1 roll widthshow}bind def 44 | /S{moveto 0 exch ashow}bind def 45 | /T{moveto 0 exch 0 SC 5 2 roll awidthshow}bind def 46 | /SF{ 47 | findfont exch 48 | [exch dup 0 exch 0 exch neg 0 0]makefont 49 | dup setfont 50 | [exch/setfont cvx]cvx bind def 51 | }bind def 52 | /MF{ 53 | findfont 54 | [5 2 roll 55 | 0 3 1 roll 56 | neg 0 0]makefont 57 | dup setfont 58 | [exch/setfont cvx]cvx bind def 59 | }bind def 60 | /level0 0 def 61 | /RES 0 def 62 | /PL 0 def 63 | /LS 0 def 64 | /MANUAL{ 65 | statusdict begin/manualfeed true store end 66 | }bind def 67 | /PLG{ 68 | gsave newpath clippath pathbbox grestore 69 | exch pop add exch pop 70 | }bind def 71 | /BP{ 72 | /level0 save def 73 | 1 setlinecap 74 | 1 setlinejoin 75 | DEFS/BPhook known{DEFS begin BPhook end}if 76 | 72 RES div dup scale 77 | LS{ 78 | 90 rotate 79 | }{ 80 | 0 PL translate 81 | }ifelse 82 | 1 -1 scale 83 | }bind def 84 | /EP{ 85 | level0 restore 86 | showpage 87 | }def 88 | /DA{ 89 | newpath arcn stroke 90 | }bind def 91 | /SN{ 92 | transform 93 | .25 sub exch .25 sub exch 94 | round .25 add exch round .25 add exch 95 | itransform 96 | }bind def 97 | /DL{ 98 | SN 99 | moveto 100 | SN 101 | lineto stroke 102 | }bind def 103 | /DC{ 104 | newpath 0 360 arc closepath 105 | }bind def 106 | /TM matrix def 107 | /DE{ 108 | TM currentmatrix pop 109 | translate scale newpath 0 0 .5 0 360 arc closepath 110 | TM setmatrix 111 | }bind def 112 | /RC/rcurveto load def 113 | /RL/rlineto load def 114 | /ST/stroke load def 115 | /MT/moveto load def 116 | /CL/closepath load def 117 | /Fr{ 118 | setrgbcolor fill 119 | }bind def 120 | /setcmykcolor where{ 121 | pop 122 | /Fk{ 123 | setcmykcolor fill 124 | }bind def 125 | }if 126 | /Fg{ 127 | setgray fill 128 | }bind def 129 | /FL/fill load def 130 | /LW/setlinewidth load def 131 | /Cr/setrgbcolor load def 132 | /setcmykcolor where{ 133 | pop 134 | /Ck/setcmykcolor load def 135 | }if 136 | /Cg/setgray load def 137 | /RE{ 138 | findfont 139 | dup maxlength 1 index/FontName known not{1 add}if dict begin 140 | { 141 | 1 index/FID ne 142 | 2 index/UniqueID ne 143 | and 144 | {def}{pop pop}ifelse 145 | }forall 146 | /Encoding exch def 147 | dup/FontName exch def 148 | currentdict end definefont pop 149 | }bind def 150 | /DEFS 0 def 151 | /EBEGIN{ 152 | moveto 153 | DEFS begin 154 | }bind def 155 | /EEND/end load def 156 | /CNT 0 def 157 | /level1 0 def 158 | /PBEGIN{ 159 | /level1 save def 160 | translate 161 | div 3 1 roll div exch scale 162 | neg exch neg exch translate 163 | 0 setgray 164 | 0 setlinecap 165 | 1 setlinewidth 166 | 0 setlinejoin 167 | 10 setmiterlimit 168 | []0 setdash 169 | /setstrokeadjust where{ 170 | pop 171 | false setstrokeadjust 172 | }if 173 | /setoverprint where{ 174 | pop 175 | false setoverprint 176 | }if 177 | newpath 178 | /CNT countdictstack def 179 | userdict begin 180 | /showpage{}def 181 | /setpagedevice{}def 182 | mark 183 | }bind def 184 | /PEND{ 185 | cleartomark 186 | countdictstack CNT sub{end}repeat 187 | level1 restore 188 | }bind def 189 | end def 190 | /setpacking where{ 191 | pop 192 | setpacking 193 | }if 194 | %%EndResource 195 | %%EndProlog 196 | %%BeginSetup 197 | %%BeginFeature: *PageSize Default 198 | << /PageSize [ 612 792 ] /ImagingBBox null >> setpagedevice 199 | %%EndFeature 200 | %%IncludeResource: font Times-BoldItalic 201 | %%IncludeResource: font Times-Roman 202 | %%IncludeResource: font Times-Bold 203 | grops begin/DEFS 1 dict def DEFS begin/u{.001 mul}bind def end/RES 72 204 | def/PL 792 def/LS false def/ENC0[/asciicircum/asciitilde/Scaron/Zcaron 205 | /scaron/zcaron/Ydieresis/trademark/quotesingle/Euro/.notdef/.notdef 206 | /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef 207 | /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef 208 | /.notdef/.notdef/space/exclam/quotedbl/numbersign/dollar/percent 209 | /ampersand/quoteright/parenleft/parenright/asterisk/plus/comma/hyphen 210 | /period/slash/zero/one/two/three/four/five/six/seven/eight/nine/colon 211 | /semicolon/less/equal/greater/question/at/A/B/C/D/E/F/G/H/I/J/K/L/M/N/O 212 | /P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash/bracketright/circumflex 213 | /underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y 214 | /z/braceleft/bar/braceright/tilde/.notdef/quotesinglbase/guillemotleft 215 | /guillemotright/bullet/florin/fraction/perthousand/dagger/daggerdbl 216 | /endash/emdash/ff/fi/fl/ffi/ffl/dotlessi/dotlessj/grave/hungarumlaut 217 | /dotaccent/breve/caron/ring/ogonek/quotedblleft/quotedblright/oe/lslash 218 | /quotedblbase/OE/Lslash/.notdef/exclamdown/cent/sterling/currency/yen 219 | /brokenbar/section/dieresis/copyright/ordfeminine/guilsinglleft 220 | /logicalnot/minus/registered/macron/degree/plusminus/twosuperior 221 | /threesuperior/acute/mu/paragraph/periodcentered/cedilla/onesuperior 222 | /ordmasculine/guilsinglright/onequarter/onehalf/threequarters 223 | /questiondown/Agrave/Aacute/Acircumflex/Atilde/Adieresis/Aring/AE 224 | /Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute/Icircumflex 225 | /Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis 226 | /multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn 227 | /germandbls/agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla 228 | /egrave/eacute/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis 229 | /eth/ntilde/ograve/oacute/ocircumflex/otilde/odieresis/divide/oslash 230 | /ugrave/uacute/ucircumflex/udieresis/yacute/thorn/ydieresis]def 231 | /Times-Bold@0 ENC0/Times-Bold RE/Times-Roman@0 ENC0/Times-Roman RE 232 | /Times-BoldItalic@0 ENC0/Times-BoldItalic RE 233 | %%EndSetup 234 | %%Page: 1 1 235 | %%BeginPageSetup 236 | BP 237 | %%EndPageSetup 238 | /F0 10/Times-BoldItalic@0 SF(SELECT)53.105 44.2 Q/F1 10/Times-Roman@0 SF 239 | (Statement)52 56.2 Q .4 LW 116.136 48 107.136 48 DL 125.136 48 MT -7.2 240 | 1.8 RL 0 -3.6 RL CL 0 Fg 125.136 48 MT -7.2 1.8 RL 0 -3.6 RL CL .1 LW 0 241 | Cg ST .4 LW 117.936 48 116.136 48 DL 195.336 62.4 MT 0 -28.8 RL -70.2 0 242 | RL 0 28.8 RL CL ST/F2 10/Times-Bold@0 SF(SELECT)140.47 50.2 Q 204.336 48 243 | 195.336 48 DL 213.336 48 MT -7.2 1.8 RL 0 -3.6 RL CL 0 Fg 213.336 48 MT 244 | -7.2 1.8 RL 0 -3.6 RL CL .1 LW 0 Cg ST .4 LW 206.136 48 204.336 48 DL 245 | 227.736 48 14.4 DC ST F1(*)225.236 50.2 Q 251.136 48 242.136 48 DL 246 | 204.336 91.2 204.336 48 DL 213.336 91.2 MT -7.2 1.8 RL 0 -3.6 RL CL 0 Fg 247 | 213.336 91.2 MT -7.2 1.8 RL 0 -3.6 RL CL .1 LW 0 Cg ST .4 LW 206.136 248 | 91.2 204.336 91.2 DL 283.536 105.6 MT 0 -28.8 RL -70.2 0 RL 0 28.8 RL CL 249 | ST(Deri)232.495 87.4 Q -.15(ve)-.25 G(d).15 E(Column)232.285 99.4 Q 250 | 292.536 91.2 283.536 91.2 DL 248.4 134.4 14.4 DC ST(,)247.15 136.6 Q 251 | 262.8 134.4 MT 7.2 -1.8 RL 0 3.6 RL CL 0 Fg 262.8 134.4 MT 7.2 -1.8 RL 0 252 | 3.6 RL CL .1 LW 0 Cg ST .4 LW 292.464 134.4 292.464 91.2 DL 270 134.4 253 | 292.464 134.4 DL 204.336 91.2 MT 1.8 7.2 RL -3.6 0 RL CL 0 Fg 204.336 254 | 91.2 MT 1.8 7.2 RL -3.6 0 RL CL .1 LW 0 Cg ST .4 LW 204.264 134.4 234 255 | 134.4 DL 204.336 98.4 204.336 134.4 DL 296.928 91.2 292.464 91.2 DL 297 256 | 48 MT 1.8 7.2 RL -3.6 0 RL CL 0 Fg 297 48 MT 1.8 7.2 RL -3.6 0 RL CL .1 257 | LW 0 Cg ST .4 LW 297 55.2 297 91.2 DL 301.536 48 251.136 48 DL 310.464 258 | 48 MT -7.2 1.8 RL 0 -3.6 RL CL 0 Fg 310.464 48 MT -7.2 1.8 RL 0 -3.6 RL 259 | CL .1 LW 0 Cg ST .4 LW 303.336 48 301.536 48 DL 380.664 62.4 MT 0 -28.8 260 | RL -70.2 0 RL 0 28.8 RL CL ST -.8(Ta)334.615 50.2 S(ble).8 E 389.664 48 261 | 380.664 48 DL 398.664 48 MT -7.2 1.8 RL 0 -3.6 RL CL 0 Fg 398.664 48 MT 262 | -7.2 1.8 RL 0 -3.6 RL CL .1 LW 0 Cg ST .4 LW 391.464 48 389.664 48 DL 263 | (Deri)56.095 181 Q -.15(ve)-.25 G(d).15 E(Column)55.885 193 Q 116.136 264 | 184.8 107.136 184.8 DL 125.136 184.8 MT -7.2 1.8 RL 0 -3.6 RL CL 0 Fg 265 | 125.136 184.8 MT -7.2 1.8 RL 0 -3.6 RL CL .1 LW 0 Cg ST .4 LW 117.936 266 | 184.8 116.136 184.8 DL 195.336 199.2 MT 0 -28.8 RL -70.2 0 RL 0 28.8 RL 267 | CL ST(Scalar)147.705 181 Q(Expression)137.98 193 Q 204.336 184.8 195.336 268 | 184.8 DL 292.536 184.8 204.336 184.8 DL 204.336 213.6 204.336 184.8 DL 269 | 213.336 213.6 MT -7.2 1.8 RL 0 -3.6 RL CL 0 Fg 213.336 213.6 MT -7.2 1.8 270 | RL 0 -3.6 RL CL .1 LW 0 Cg ST .4 LW 206.136 213.6 204.336 213.6 DL 271 | 283.536 228 MT 0 -28.8 RL -70.2 0 RL 0 28.8 RL CL ST F2(AS)242.01 215.8 272 | Q 292.536 213.6 283.536 213.6 DL 301.536 213.6 MT -7.2 1.8 RL 0 -3.6 RL 273 | CL 0 Fg 301.536 213.6 MT -7.2 1.8 RL 0 -3.6 RL CL .1 LW 0 Cg ST .4 LW 274 | 294.264 213.6 292.464 213.6 DL 371.664 228 MT 0 -28.8 RL -70.2 0 RL 0 275 | 28.8 RL CL ST F1(Column)320.485 209.8 Q(Name)324.66 221.8 Q 380.736 276 | 213.6 371.736 213.6 DL 380.736 184.8 MT 1.8 7.2 RL -3.6 0 RL CL 0 Fg 277 | 380.736 184.8 MT 1.8 7.2 RL -3.6 0 RL CL .1 LW 0 Cg ST .4 LW 380.736 192 278 | 380.736 213.6 DL 385.2 184.8 292.464 184.8 DL 394.2 184.8 MT -7.2 1.8 RL 279 | 0 -3.6 RL CL 0 Fg 394.2 184.8 MT -7.2 1.8 RL 0 -3.6 RL CL .1 LW 0 Cg ST 280 | .4 LW 387 184.8 385.2 184.8 DL -.8(Ta)61.015 266.2 S(ble).8 E 116.136 281 | 264 107.136 264 DL 125.136 264 MT -7.2 1.8 RL 0 -3.6 RL CL 0 Fg 125.136 282 | 264 MT -7.2 1.8 RL 0 -3.6 RL CL .1 LW 0 Cg ST .4 LW 117.936 264 116.136 283 | 264 DL 195.336 278.4 MT 0 -28.8 RL -70.2 0 RL 0 28.8 RL CL ST F2(FR) 284 | 145.075 266.2 Q(OM)-.3 E 204.336 264 195.336 264 DL 213.336 264 MT -7.2 285 | 1.8 RL 0 -3.6 RL CL 0 Fg 213.336 264 MT -7.2 1.8 RL 0 -3.6 RL CL .1 LW 0 286 | Cg ST .4 LW 206.136 264 204.336 264 DL 283.536 278.4 MT 0 -28.8 RL -70.2 287 | 0 RL 0 28.8 RL CL ST F1 -.8(Ta)237.415 260.2 S(ble).8 E(Name)236.46 288 | 272.2 Q 292.536 264 283.536 264 DL 248.4 307.2 14.4 DC ST(,)247.15 309.4 289 | Q 262.8 307.2 MT 7.2 -1.8 RL 0 3.6 RL CL 0 Fg 262.8 307.2 MT 7.2 -1.8 RL 290 | 0 3.6 RL CL .1 LW 0 Cg ST .4 LW 292.464 307.2 292.464 264 DL 270 307.2 291 | 292.464 307.2 DL 204.336 264 MT 1.8 7.2 RL -3.6 0 RL CL 0 Fg 204.336 264 292 | MT 1.8 7.2 RL -3.6 0 RL CL .1 LW 0 Cg ST .4 LW 204.336 307.2 234 307.2 293 | DL 204.336 271.2 204.336 307.2 DL 296.928 264 292.464 264 DL 385.2 264 294 | 297 264 DL 297 292.8 297 264 DL 306 292.8 MT -7.2 1.8 RL 0 -3.6 RL CL 0 295 | Fg 306 292.8 MT -7.2 1.8 RL 0 -3.6 RL CL .1 LW 0 Cg ST .4 LW 298.8 292.8 296 | 297 292.8 DL 376.2 307.2 MT 0 -28.8 RL -70.2 0 RL 0 28.8 RL CL ST F0 297 | (WHERE)322.724 289 Q F1(Clause)327.454 301 Q 385.2 292.8 376.2 292.8 DL 298 | 385.2 264 MT 1.8 7.2 RL -3.6 0 RL CL 0 Fg 385.2 264 MT 1.8 7.2 RL -3.6 0 299 | RL CL .1 LW 0 Cg ST .4 LW 385.2 271.2 385.2 292.8 DL 389.664 264 385.2 300 | 264 DL 477.864 264 389.664 264 DL 389.664 292.8 389.664 264 DL 398.664 301 | 292.8 MT -7.2 1.8 RL 0 -3.6 RL CL 0 Fg 398.664 292.8 MT -7.2 1.8 RL 0 302 | -3.6 RL CL .1 LW 0 Cg ST .4 LW 391.464 292.8 389.664 292.8 DL 468.864 303 | 307.2 MT 0 -28.8 RL -70.2 0 RL 0 28.8 RL CL ST F0(GR)409.14 289 Q 304 | (OUP BY)-.4 E F1(Clause)420.19 301 Q 477.864 292.8 468.864 292.8 DL 305 | 477.864 264 MT 1.8 7.2 RL -3.6 0 RL CL 0 Fg 477.864 264 MT 1.8 7.2 RL 306 | -3.6 0 RL CL .1 LW 0 Cg ST .4 LW 477.864 271.2 477.864 292.8 DL 482.328 307 | 264 477.864 264 DL 570.6 264 482.4 264 DL 482.4 292.8 482.4 264 DL 491.4 308 | 292.8 MT -7.2 1.8 RL 0 -3.6 RL CL 0 Fg 491.4 292.8 MT -7.2 1.8 RL 0 -3.6 309 | RL CL .1 LW 0 Cg ST .4 LW 484.2 292.8 482.4 292.8 DL 561.6 307.2 MT 0 310 | -28.8 RL -70.2 0 RL 0 28.8 RL CL ST F0(ORDER BY)501.599 289 Q F1(Clause) 311 | 512.854 301 Q 570.6 292.8 561.6 292.8 DL 570.6 264 MT 1.8 7.2 RL -3.6 0 312 | RL CL 0 Fg 570.6 264 MT 1.8 7.2 RL -3.6 0 RL CL .1 LW 0 Cg ST .4 LW 313 | 570.6 271.2 570.6 292.8 DL 575.064 264 570.6 264 DL 584.064 264 MT -7.2 314 | 1.8 RL 0 -3.6 RL CL 0 Fg 584.064 264 MT -7.2 1.8 RL 0 -3.6 RL CL .1 LW 0 315 | Cg ST .4 LW 576.864 264 575.064 264 DL F0(WHERE)53.66 353.8 Q F1(Clause) 316 | 58.39 365.8 Q 116.136 357.6 107.136 357.6 DL 125.136 357.6 MT -7.2 1.8 317 | RL 0 -3.6 RL CL 0 Fg 125.136 357.6 MT -7.2 1.8 RL 0 -3.6 RL CL .1 LW 0 318 | Cg ST .4 LW 117.936 357.6 116.136 357.6 DL 195.336 372 MT 0 -28.8 RL 319 | -70.2 0 RL 0 28.8 RL CL ST F2(WHERE)141.03 359.8 Q 204.336 357.6 195.336 320 | 357.6 DL 213.336 357.6 MT -7.2 1.8 RL 0 -3.6 RL CL 0 Fg 213.336 357.6 MT 321 | -7.2 1.8 RL 0 -3.6 RL CL .1 LW 0 Cg ST .4 LW 206.136 357.6 204.336 357.6 322 | DL 283.536 372 MT 0 -28.8 RL -70.2 0 RL 0 28.8 RL CL ST F1(Condition) 323 | 228.395 359.8 Q 292.536 357.6 283.536 357.6 DL 301.536 357.6 MT -7.2 1.8 324 | RL 0 -3.6 RL CL 0 Fg 301.536 357.6 MT -7.2 1.8 RL 0 -3.6 RL CL .1 LW 0 325 | Cg ST .4 LW 294.264 357.6 292.464 357.6 DL F0(GR)47.34 404.2 Q(OUP BY) 326 | -.4 E F1(Clause)58.39 416.2 Q 116.136 408 107.136 408 DL 125.136 408 MT 327 | -7.2 1.8 RL 0 -3.6 RL CL 0 Fg 125.136 408 MT -7.2 1.8 RL 0 -3.6 RL CL .1 328 | LW 0 Cg ST .4 LW 117.936 408 116.136 408 DL 195.336 422.4 MT 0 -28.8 RL 329 | -70.2 0 RL 0 28.8 RL CL ST F2(GR)142.295 410.2 Q(OUP)-.3 E 204.336 408 330 | 195.336 408 DL 213.336 408 MT -7.2 1.8 RL 0 -3.6 RL CL 0 Fg 213.336 408 331 | MT -7.2 1.8 RL 0 -3.6 RL CL .1 LW 0 Cg ST .4 LW 206.136 408 204.336 408 332 | DL 283.536 422.4 MT 0 -28.8 RL -70.2 0 RL 0 28.8 RL CL ST(BY)241.455 333 | 410.2 Q 292.536 408 283.536 408 DL 301.536 408 MT -7.2 1.8 RL 0 -3.6 RL 334 | CL 0 Fg 301.536 408 MT -7.2 1.8 RL 0 -3.6 RL CL .1 LW 0 Cg ST .4 LW 335 | 294.264 408 292.464 408 DL 371.664 422.4 MT 0 -28.8 RL -70.2 0 RL 0 28.8 336 | RL CL ST F1(Column)320.485 404.2 Q(Name)324.66 416.2 Q 380.664 408 337 | 371.664 408 DL 336.6 451.2 14.4 DC ST(,)335.35 453.4 Q 351 451.2 MT 7.2 338 | -1.8 RL 0 3.6 RL CL 0 Fg 351 451.2 MT 7.2 -1.8 RL 0 3.6 RL CL .1 LW 0 Cg 339 | ST .4 LW 380.664 451.2 380.664 408 DL 358.2 451.2 380.664 451.2 DL 340 | 292.464 408 MT 1.8 7.2 RL -3.6 0 RL CL 0 Fg 292.464 408 MT 1.8 7.2 RL 341 | -3.6 0 RL CL .1 LW 0 Cg ST .4 LW 292.536 451.2 322.2 451.2 DL 292.464 342 | 415.2 292.464 451.2 DL 385.128 408 380.664 408 DL 394.2 408 MT -7.2 1.8 343 | RL 0 -3.6 RL CL 0 Fg 394.2 408 MT -7.2 1.8 RL 0 -3.6 RL CL .1 LW 0 Cg ST 344 | .4 LW 387 408 385.2 408 DL F0(ORDER BY)47.135 497.8 Q F1(Clause)58.39 345 | 509.8 Q 116.136 501.6 107.136 501.6 DL 125.136 501.6 MT -7.2 1.8 RL 0 346 | -3.6 RL CL 0 Fg 125.136 501.6 MT -7.2 1.8 RL 0 -3.6 RL CL .1 LW 0 Cg ST 347 | .4 LW 117.936 501.6 116.136 501.6 DL 195.336 516 MT 0 -28.8 RL -70.2 0 348 | RL 0 28.8 RL CL ST F2(ORDER)142.145 503.8 Q 204.336 501.6 195.336 501.6 349 | DL 213.336 501.6 MT -7.2 1.8 RL 0 -3.6 RL CL 0 Fg 213.336 501.6 MT -7.2 350 | 1.8 RL 0 -3.6 RL CL .1 LW 0 Cg ST .4 LW 206.136 501.6 204.336 501.6 DL 351 | 283.536 516 MT 0 -28.8 RL -70.2 0 RL 0 28.8 RL CL ST(BY)241.455 503.8 Q 352 | 292.536 501.6 283.536 501.6 DL 301.536 501.6 MT -7.2 1.8 RL 0 -3.6 RL CL 353 | 0 Fg 301.536 501.6 MT -7.2 1.8 RL 0 -3.6 RL CL .1 LW 0 Cg ST .4 LW 354 | 294.264 501.6 292.464 501.6 DL 371.664 516 MT 0 -28.8 RL -70.2 0 RL 0 355 | 28.8 RL CL ST F1(Column)320.485 497.8 Q(Name)324.66 509.8 Q 380.736 356 | 501.6 371.736 501.6 DL 468.936 501.6 380.736 501.6 DL 380.736 530.4 357 | 380.736 501.6 DL 389.736 530.4 MT -7.2 1.8 RL 0 -3.6 RL CL 0 Fg 389.736 358 | 530.4 MT -7.2 1.8 RL 0 -3.6 RL CL .1 LW 0 Cg ST .4 LW 382.536 530.4 359 | 380.736 530.4 DL 459.936 544.8 MT 0 -28.8 RL -70.2 0 RL 0 28.8 RL CL ST 360 | F2(ASCENDING)394.8 532.6 Q 468.936 530.4 459.936 530.4 DL 380.736 573.6 361 | 380.736 530.4 DL 389.736 573.6 MT -7.2 1.8 RL 0 -3.6 RL CL 0 Fg 389.736 362 | 573.6 MT -7.2 1.8 RL 0 -3.6 RL CL .1 LW 0 Cg ST .4 LW 382.536 573.6 363 | 380.736 573.6 DL 459.936 588 MT 0 -28.8 RL -70.2 0 RL 0 28.8 RL CL ST 364 | (DESCENDING)391.465 575.8 Q 468.936 573.6 459.936 573.6 DL 468.936 530.4 365 | MT 1.8 7.2 RL -3.6 0 RL CL 0 Fg 468.936 530.4 MT 1.8 7.2 RL -3.6 0 RL CL 366 | .1 LW 0 Cg ST .4 LW 468.936 537.6 468.936 573.6 DL 473.4 530.4 468.936 367 | 530.4 DL 473.4 501.6 MT 1.8 7.2 RL -3.6 0 RL CL 0 Fg 473.4 501.6 MT 1.8 368 | 7.2 RL -3.6 0 RL CL .1 LW 0 Cg ST .4 LW 473.4 508.8 473.4 530.4 DL 369 | 477.936 501.6 468.936 501.6 DL 385.2 616.8 14.4 DC ST F1(,)383.95 619 Q 370 | 399.6 616.8 MT 7.2 -1.8 RL 0 3.6 RL CL 0 Fg 399.6 616.8 MT 7.2 -1.8 RL 0 371 | 3.6 RL CL .1 LW 0 Cg ST .4 LW 477.936 616.8 477.936 501.6 DL 406.8 616.8 372 | 477.936 616.8 DL 292.464 501.6 MT 1.8 7.2 RL -3.6 0 RL CL 0 Fg 292.464 373 | 501.6 MT 1.8 7.2 RL -3.6 0 RL CL .1 LW 0 Cg ST .4 LW 292.464 616.8 370.8 374 | 616.8 DL 292.464 508.8 292.464 616.8 DL 482.4 501.6 477.936 501.6 DL 375 | 491.4 501.6 MT -7.2 1.8 RL 0 -3.6 RL CL 0 Fg 491.4 501.6 MT -7.2 1.8 RL 376 | 0 -3.6 RL CL .1 LW 0 Cg ST .4 LW 484.2 501.6 482.4 501.6 DL 0 Cg EP 377 | %%Trailer 378 | end 379 | %%EOF 380 | -------------------------------------------------------------------------------- /sql.lang: -------------------------------------------------------------------------------- 1 | type = "VARCHAR|TINYINT|TEXT|DATE|SMALLINT|MEDIUMINT|INT|INTEGER|BIGINT", 2 | "FLOAT|DOUBLE|DECIMAL|DATETIME|TIMESTAMP|TIME|YEAR|UNSIGNED", 3 | "CHAR|CHARACTER|VARYING|TINYBLOB|TINYTEXT|BLOB|MEDIUMBLOB|MEDIUMTEXT", 4 | "LONGBLOB|LONGTEXT|ENUM|BOOL|BINARY|VARBINARY" nonsensitive 5 | 6 | keyword = "ALL|ASC|AS|ALTER|AND|ADD|AUTO_INCREMENT", 7 | "BETWEEN|BINARY|BOTH|BY|BOOLEAN", 8 | "CHANGE|CHECK|COLUMNS|COLUMN|CROSS|CREATE", 9 | "DATABASES|DATABASE|DATA|DELAYED|DESCRIBE|DESC|DISTINCT|DELETE|DROP|DEFAULT", 10 | "ENCLOSED|ESCAPED|EXISTS|EXPLAIN", 11 | "FIELDS|FIELD|FLUSH|FOR|FOREIGN|FUNCTION|FROM", 12 | "GROUP|GRANT", 13 | "HAVING", 14 | "IGNORE|INDEX|INFILE|INSERT|INNER|INTO|IDENTIFIED|IN|IS|IF", 15 | "JOIN", 16 | "KEYS|KILL|KEY", 17 | "LEADING|LIKE|LIMIT|LINES|LOAD|LOCAL|LOCK|LOW_PRIORITY|LEFT|LANGUAGE", 18 | "MODIFY", 19 | "NATURAL|NOT|NULL|NEXTVAL", 20 | "OPTIMIZE|OPTION|OPTIONALLY|ORDER|OUTFILE|OR|OUTER|ON", 21 | "PROCEDURE","PROCEDURAL|PRIMARY", 22 | "READ|REFERENCES|REGEXP|RENAME|REPLACE|RETURN|REVOKE|RLIKE|RIGHT", 23 | "SHOW|SONAME|STATUS|STRAIGHT_JOIN|SELECT|SETVAL|SET", 24 | "TABLES|TERMINATED|TO|TRAILING","TRUNCATE|TABLE|TEMPORARY|TRIGGER|TRUSTED", 25 | "UNION|UNIQUE|UNLOCK|USE|USING|UPDATE", 26 | "VALUES|VARIABLES|VIEW", 27 | "WITH|WRITE|WHERE", 28 | "ZEROFILL|TYPE", 29 | "XOR" 30 | nonsensitive 31 | 32 | include "c_string.lang" 33 | 34 | environment string delim "`" "`" begin 35 | specialchar = $SPECIALCHAR 36 | end 37 | 38 | include "script_comment.lang" 39 | 40 | include "c_comment.lang" 41 | 42 | comment start "--" 43 | 44 | include "symbols.lang" 45 | 46 | include "number.lang" -------------------------------------------------------------------------------- /syntax.pic: -------------------------------------------------------------------------------- 1 | linewid = linewid/2; 2 | 3 | define begin_group { 4 | [Start: Here; 5 | } 6 | define end_group { 7 | End: Here;] with .Start at Here; 8 | move to last [].End; 9 | } 10 | 11 | define terminal { 12 | begin_group(); 13 | arrow; 14 | command ".FT TT"; 15 | command ".DOC_PT_SIZE +4"; 16 | circle $1; 17 | command ".DOC_PT_SIZE -4"; 18 | command ".FT R"; 19 | line; 20 | end_group(); 21 | } 22 | 23 | define nonterminal { 24 | begin_group(); 25 | arrow; 26 | command ".FT I"; 27 | box $1; 28 | command ".FT R"; 29 | line; 30 | end_group(); 31 | } 32 | 33 | define keyword { 34 | begin_group(); 35 | arrow; 36 | command ".FT TT"; 37 | box $1; 38 | command ".FT R"; 39 | line; 40 | end_group(); 41 | } 42 | 43 | define empty { 44 | begin_group(); 45 | # straight line, as long as a box would be 46 | line linewid+boxwid+linewid; 47 | end_group(); 48 | } 49 | 50 | ### 51 | ### repeat(block); 52 | ### Block must have labels `Start` and `End`. 53 | ### 54 | define repeat { 55 | line from $1.End to $1.se - (0,circlerad*2); 56 | arrow to ($1.Start,Here) then to $1.Start; 57 | line from $1.End right linewid/2; 58 | } 59 | 60 | ### 61 | ### repeat(block,terminal_symbol); 62 | ### 63 | define repeat_with { 64 | command ".FT TT"; 65 | command ".DOC_PT_SIZE +4"; 66 | circle at bottom of $1 - (0,circlerad*2) $2; 67 | command ".DOC_PT_SIZE -4"; 68 | command ".FT R"; 69 | 70 | arrow from $1.End to ($1.End,last circle) then \ 71 | to east of last circle; 72 | arrow from west of last circle to ($1.Start,last circle .e) then \ 73 | to $1.Start; 74 | line from $1.End right linewid/2; 75 | } 76 | 77 | ### begin_alt(base); 78 | define begin_alt { 79 | line from $1.Start to $1.sw - (0,boxht); 80 | begin_group(); 81 | } 82 | 83 | ### end_alt(base); 84 | define end_alt { 85 | end_group(); 86 | # base might be smaller than alternative 87 | if (Here.x < $1.End.x) then { 88 | line to ($1.End,Here); 89 | } 90 | arrow to (Here,$1.End); 91 | # Extend end of base if it is smaller than alternative 92 | # and leave linewid/2 space for next alternative 93 | line from $1.End to Here + (linewid/2,0); 94 | } 95 | 96 | define begin_rule { 97 | move down; 98 | right; 99 | command ".FT I"; 100 | {$1 at Here - (boxwid/2,0)} 101 | command ".FT R"; 102 | begin_group(); 103 | line; 104 | } 105 | 106 | define end_rule { 107 | arrow; 108 | end_group(); 109 | move to last [].sw; 110 | } 111 | -------------------------------------------------------------------------------- /uml-graph/sequence.pic: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhaberkorn/groff-tools/cdd7596fe77edfd2cc655dbd22bca0949d82ead2/uml-graph/sequence.pic -------------------------------------------------------------------------------- /uml.sno: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/snobol4 -b 2 | 3 | &anchor = 1 4 | 5 | float = span("0123456789.") 6 | 7 | count = 0 8 | lineno = 1 9 | 10 | loop line = input :f(end) 11 | line ".lf " float . lineno :s(next) 12 | line ".UML" rem . options :s(pipe) 13 | lineno = lineno + 1 14 | next output = line :(loop) 15 | 16 | pipe filename = "uml_temp" (count = count + 1) ".pdf" 17 | output(.pipe, 100,, 18 | + "| plantuml -pipe -tsvg -failonerror -config plantuml.cfg | " 19 | + "rsvg-convert -f pdf -o " filename) 20 | pipe = "@startuml" 21 | 22 | pipe_l line = input 23 | lineno = lineno + 1 24 | line ".UML" :s(close) 25 | pipe = line :(pipe_l) 26 | 27 | close pipe = "@enduml" 28 | endfile(100) 29 | 30 | * get PDF dimensions 31 | input(.pipe, 100,, "|pdfinfo " filename) 32 | get_info 33 | pipe "Page size:" span(" ") float . width " x " float . height :f(get_info) 34 | endfile(100) 35 | 36 | output = ".PDF_IMAGE " filename " " width "p " height "p" options 37 | output = ".lf " (lineno + 1) :(loop) 38 | 39 | end 40 | 41 | --------------------------------------------------------------------------------