2
BNF Converter: Latex Generator
3
Copyright (C) 2004 Author: Markus Forberg, Aarne Ranta
5
This program is free software; you can redistribute it and/or modify
6
it under the terms of the GNU General Public License as published by
7
the Free Software Foundation; either version 2 of the License, or
8
(at your option) any later version.
10
This program is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
GNU General Public License for more details.
15
You should have received a copy of the GNU General Public License
16
along with this program; if not, write to the Free Software
17
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20
module CFtoLatex (cfToLatex)where
23
import AbsBNF (Reg (..))
25
import Data.List (nub,intersperse)
27
cfToLatex :: String -> CF -> String
28
cfToLatex name cf = unlines [
38
introduction :: String
41
"\nThis document was automatically generated by ",
42
"the {\\em BNF-Converter}.",
43
" It was generated together with the lexer, the parser, and the",
44
" abstract syntax module, which guarantees that the document",
45
" matches with the implementation of the language (provided no",
46
" hand-hacking has taken place).\n"
49
prtTerminals :: String -> CF -> String
50
prtTerminals name cf = unlines [
51
"\\section*{The lexical structure of " ++ name ++ "}",
53
"\\subsection*{Literals}",
55
unlines (map prtOwnToken (tokenPragmas cf)),
56
"\\subsection*{Reserved words and symbols}",
59
"\\subsection*{Comments}",
60
prtComments $ comments cf
63
identSection cf = if not (hasIdent cf) then [] else
65
"\\subsection*{Identifiers}",
69
prtIdentifiers :: String
70
prtIdentifiers = unlines
72
"Identifiers \\nonterminal{Ident} are unquoted strings beginning with a letter,",
73
"followed by any combination of letters, digits, and the characters {\\tt \\_ '},",
74
"reserved words excluded."
77
prtLiterals :: String -> CF -> String
79
unlines $ map stringLit $
80
filter (`notElem` ["Ident"]) $
83
stringLit :: String -> String
84
stringLit cat = unlines $ case cat of
85
"Char" -> ["Character literals \\nonterminal{Char}\\ have the form",
86
"\\terminal{'}$c$\\terminal{'}, where $c$ is any single character.",
89
"String" -> ["String literals \\nonterminal{String}\\ have the form",
90
"\\terminal{\"}$x$\\terminal{\"}, where $x$ is any sequence of any characters",
91
"except \\terminal{\"}\\ unless preceded by \\verb6\\6.",
93
"Integer" -> ["Integer literals \\nonterminal{Int}\\ are nonempty sequences of digits.",
95
"Double" -> ["Double-precision float literals \\nonterminal{Double}\\ have the structure",
96
"indicated by the regular expression" +++
97
"$\\nonterminal{digit}+ \\mbox{{\\it `.'}} \\nonterminal{digit}+ (\\mbox{{\\it `e'}} \\mbox{{\\it `-'}}? \\nonterminal{digit}+)?$ i.e.\\",
98
"two sequences of digits separated by a decimal point, optionally",
99
"followed by an unsigned or negative exponent.",
103
prtOwnToken (name,reg) = unlines
104
[name +++ "literals are recognized by the regular expression",
110
prtComments :: ([(String,String)],[String]) -> String
111
prtComments (xs,ys) = concat
114
"There are no single-line comments in the grammar. \\\\"
116
"Single-line comments begin with " ++ sing ++". \\\\",
118
"There are no multiple-line comments in the grammar."
120
"Multiple-line comments are enclosed with " ++ mult ++"."
123
sing = concat $ intersperse ", " $ map (symbol.prt) ys
124
mult = concat $ intersperse ", " $
125
map (\(x,y) -> (symbol (prt x))
129
prtSymb :: String -> CF -> String
130
prtSymb name cf = case symbols cf of
131
[] -> "\nThere are no symbols in " ++ name ++ ".\\\\\n"
132
xs -> "The symbols used in " ++ name ++ " are the following: \\\\\n"
134
(tabular 3 $ three $ map (symbol.prt) xs)
136
prtReserved :: String -> CF -> String
137
prtReserved name cf = case reservedWords cf of
138
[] -> stringRes name ++
139
"\nThere are no reserved words in " ++ name ++ ".\\\\\n"
140
xs -> stringRes name ++
141
(tabular 3 $ three $ map (reserved.prt) xs)
143
stringRes :: String -> String
144
stringRes name = concat
145
["The set of reserved words is the set of terminals ",
146
"appearing in the grammar. Those reserved words ",
147
"that consist of non-letter characters are called symbols, and ",
148
"they are treated in a different way from those that ",
149
"are similar to identifiers. The lexer ",
150
"follows rules familiar from languages ",
151
"like Haskell, C, and Java, including longest match ",
152
"and spacing conventions.",
154
"The reserved words used in " ++ name ++ " are the following: \\\\\n"]
156
three :: [String] -> [[String]]
158
three [x] = [[x,[],[]]]
159
three [x,y] = [[x,y,[]]]
160
three (x:y:z:xs) = [x,y,z] : three xs
162
prtBNF :: String -> CF -> String
163
prtBNF name cf = unlines [
164
"\\section*{The syntactic structure of " ++ name ++"}",
165
"Non-terminals are enclosed between $\\langle$ and $\\rangle$. ",
166
"The symbols " ++ arrow ++ " (production), " ++
167
delimiter ++" (union) ",
168
"and " ++ empty ++ " (empty rule) belong to the BNF notation. ",
169
"All other symbols are terminals.\\\\",
170
prtRules (ruleGroups cf)
173
prtRules :: [(Cat,[Rule])] -> String
176
= tabular 3 [[nonterminal c,arrow,[]]] ++ prtRules xs
177
prtRules ((c,(r:rs)):xs)
178
= tabular 3 ([[nonterminal c,arrow,prtSymbols $ rhsRule r]] ++
179
[[[],delimiter,prtSymbols (rhsRule y)] | y <- rs]) ++
182
prtSymbols :: [Either Cat String] -> String
183
prtSymbols [] = empty
184
prtSymbols xs = foldr (+++) [] (map p xs)
185
where p (Left r) = nonterminal r --- (prt r)
186
p (Right r) = terminal (prt r)
188
prt :: String -> String
191
| elem c "$&%#_{}^" = "\\" ++ [c] ++ prt xs
192
| elem c "+=|<>-" = "{$" ++ [c] ++ "$}" ++ prt xs
193
| c == '\\' = "$\\backslash$"
195
| otherwise = c : prt xs
199
"\\newcommand{\\emptyP}{\\mbox{$\\epsilon$}}" ++++
200
"\\newcommand{\\terminal}[1]{\\mbox{{\\texttt {#1}}}}" ++++
201
"\\newcommand{\\nonterminal}[1]{\\mbox{$\\langle \\mbox{{\\sl #1 }} \\! \\rangle$}}" ++++
202
"\\newcommand{\\arrow}{\\mbox{::=}}" ++++
203
"\\newcommand{\\delimit}{\\mbox{$|$}}" ++++
204
"\\newcommand{\\reserved}[1]{\\mbox{{\\texttt {#1}}}}" ++++
205
"\\newcommand{\\literal}[1]{\\mbox{{\\texttt {#1}}}}" ++++
206
"\\newcommand{\\symb}[1]{\\mbox{{\\texttt {#1}}}}"
208
reserved :: String -> String
209
reserved s = "{\\reserved{" ++ s ++ "}}"
211
literal :: String -> String
212
literal s = "{\\literal{" ++ s ++ "}}"
217
symbol :: String -> String
218
symbol s = "{\\symb{" ++ s ++ "}}"
220
tabular :: Int -> [[String]] -> String
221
tabular n xs = "\n\\begin{tabular}{" ++ concat (replicate n "l") ++ "}\n" ++
222
concat (map (\(a:as) -> foldr (+++) "\\\\\n" (a:(map ('&':) as))) xs) ++
223
"\\end{tabular}\\\\\n"
225
terminal :: String -> String
226
terminal s = "{\\terminal{" ++ s ++ "}}"
228
nonterminal :: String -> String
229
nonterminal s = "{\\nonterminal{" ++ identCat (mkId s) ++ "}}" where
237
arrow = " {\\arrow} "
240
delimiter = " {\\delimit} "
242
beginDocument :: String -> String
244
"%This Latex file is machine-generated by the BNF-converter\n" ++++
245
"\\documentclass[a4paper,11pt]{article}" ++++
246
"\\author{BNF-converter}" ++++
247
"\\title{The Language " ++ name ++ "}" ++++
248
-- "\\usepackage{isolatin1}" ++++
249
"\\setlength{\\parindent}{0mm}" ++++
250
"\\setlength{\\parskip}{1mm}" ++++
251
"\\begin{document}\n" ++++
254
endDocument :: String
256
"\n\\end{document}\n"
258
latexRegExp :: Reg -> String
259
latexRegExp = rex (0 :: Int) where
261
RSeq reg0 reg -> ifPar i 2 $ rex 2 reg0 +++ rex 2 reg
262
RAlt reg0 reg -> ifPar i 1 $ rex 1 reg0 +++ "\\mid" +++ rex 1 reg
263
RMinus reg0 reg -> ifPar i 1 $ rex 2 reg0 +++ "-" +++ rex 2 reg
264
RStar reg -> rex 3 reg ++ "*"
265
RPlus reg -> rex 3 reg ++ "+"
266
ROpt reg -> rex 3 reg ++ "?"
268
RChar c -> "\\mbox{`" ++ prt [c] ++ "'}"
269
RAlts str -> "[" ++ "\\mbox{``" ++ prt str ++ "''}" ++ "]"
270
RSeqs str -> "\\{" ++ "\\mbox{``" ++ prt str ++ "''}" ++ "\\}"
271
RDigit -> "{\\nonterminal{digit}}"
272
RLetter -> "{\\nonterminal{letter}}"
273
RUpper -> "{\\nonterminal{upper}}"
274
RLower -> "{\\nonterminal{lower}}"
275
RAny -> "{\\nonterminal{anychar}}"
276
ifPar i j s = if i > j then "(" ++ s ++ ")" else s