~ubuntu-branches/ubuntu/utopic/bnfc/utopic

« back to all changes in this revision

Viewing changes to src/formats/haskell2/CFtoHappy.hs

  • Committer: Package Import Robot
  • Author(s): Joachim Breitner
  • Date: 2013-05-24 12:49:41 UTC
  • mfrom: (7.1.1 experimental)
  • Revision ID: package-import@ubuntu.com-20130524124941-tepbsbvdogyegb6k
Tags: 2.6.0.3-2
* Change Homepage field (Closes: #677988)
* Enable compat level 9
* Bump standards version to 3.9.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
{-
 
2
    BNF Converter: Happy Generator
 
3
    Copyright (C) 2004  Author:  Markus Forberg, Aarne Ranta
 
4
 
 
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.
 
9
 
 
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.
 
14
 
 
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
 
18
-}
 
19
 
 
20
module CFtoHappy 
 
21
       (
 
22
       cf2HappyS -- cf2HappyS :: CF -> CFCat -> String
 
23
       )
 
24
        where
 
25
 
 
26
import CF
 
27
--import Lexer
 
28
import Data.List (intersperse, sort)
 
29
import Data.Char
 
30
import Options (HappyMode(..))
 
31
-- Type declarations
 
32
 
 
33
type Rules       = [(NonTerminal,[(Pattern,Action)])]
 
34
type NonTerminal = String
 
35
type Pattern     = String
 
36
type Action      = String
 
37
type MetaVar     = String
 
38
 
 
39
-- default naming
 
40
 
 
41
moduleName  = "HappyParser"
 
42
tokenName   = "Token"
 
43
 
 
44
-- Happy mode
 
45
 
 
46
 
 
47
 
 
48
cf2HappyS :: String -> String -> String -> String -> HappyMode -> Bool -> CF -> String
 
49
---- cf2HappyS :: String -> CF -> String
 
50
cf2HappyS = cf2Happy
 
51
 
 
52
-- The main function, that given a CF and a CFCat to parse according to, 
 
53
-- generates a happy module. 
 
54
cf2Happy name absName lexName errName mode byteStrings cf 
 
55
 = unlines 
 
56
    [header name absName lexName errName mode byteStrings,
 
57
     declarations mode (allEntryPoints cf),
 
58
     tokens (cfTokens cf),
 
59
     specialToks cf,
 
60
     delimiter,
 
61
     specialRules byteStrings cf,
 
62
     prRules (rulesForHappy cf),
 
63
     finalize byteStrings cf]
 
64
 
 
65
-- construct the header.
 
66
header :: String -> String -> String -> String -> HappyMode -> Bool -> String
 
67
header modName absName lexName errName mode byteStrings = unlines 
 
68
         ["-- This Happy file was machine-generated by the BNF converter",
 
69
          "{",
 
70
          "{-# OPTIONS_GHC -fno-warn-incomplete-patterns -fno-warn-overlapping-patterns #-}",
 
71
          case mode of 
 
72
            Standard -> "module " ++ modName ++ " where" 
 
73
            GLR      -> "-- module name filled in by Happy",
 
74
          "import " ++ absName,
 
75
          "import " ++ lexName,
 
76
          "import " ++ errName,
 
77
          if byteStrings then "import qualified Data.ByteString.Char8 as BS" else "",
 
78
          "}"
 
79
         ]
 
80
 
 
81
{- ----
 
82
cf2Happy :: String -> CF -> String
 
83
cf2Happy name cf 
 
84
 = unlines 
 
85
    [header name,
 
86
     declarations (allEntryPoints cf),
 
87
     tokens (cfTokens cf),
 
88
     specialToks cf,
 
89
     delimiter,
 
90
     specialRules cf,
 
91
     prRules (rulesForHappy cf),
 
92
     finalize cf]
 
93
 
 
94
-- construct the header.
 
95
header :: String -> String
 
96
header name = unlines 
 
97
         ["-- This Happy file was machine-generated by the BNF converter",
 
98
          "{",
 
99
          "module Par" ++ name ++ " where", 
 
100
          "import Abs"++name,
 
101
          "import Lex"++name,
 
102
          "import ErrM",
 
103
          "}"
 
104
         ]
 
105
-}
 
106
 
 
107
-- The declarations of a happy file.
 
108
declarations :: HappyMode -> [NonTerminal] -> String
 
109
declarations mode ns = unlines 
 
110
                 [generateP ns,
 
111
                  case mode of 
 
112
                    Standard -> "-- no lexer declaration"
 
113
                    GLR      -> "%lexer { myLexer } { Err _ }",
 
114
                  "%monad { Err } { thenM } { returnM }",
 
115
                  "%tokentype { " ++ tokenName ++ " }"]
 
116
   where generateP []     = []
 
117
         generateP (n:ns) = concat ["%name p",n'," ",n',"\n",generateP ns]
 
118
                               where n' = identCat n
 
119
 
 
120
-- The useless delimiter symbol.
 
121
delimiter :: String
 
122
delimiter = "\n%%\n"
 
123
 
 
124
-- Generate the list of tokens and their identifiers.
 
125
tokens :: [(String,Int)] -> String
 
126
tokens toks = "%token \n" ++ prTokens toks
 
127
 where prTokens []         = []
 
128
       prTokens ((t,k):tk) = " " ++ (convert t) ++ 
 
129
                             " { " ++ oneTok t k ++ " }\n" ++
 
130
                             prTokens tk
 
131
       oneTok t k = "PT _ (TS _ " ++ show k ++ ")"
 
132
 
 
133
-- Happy doesn't allow characters such as ��� to occur in the happy file. This
 
134
-- is however not a restriction, just a naming paradigm in the happy source file.
 
135
convert :: String -> String
 
136
convert "\\" = concat ['\'':"\\\\","\'"]
 
137
convert xs   = concat ['\'':(escape xs),"\'"]
 
138
  where escape [] = []
 
139
        escape ('\'':xs) = '\\':'\'':escape xs
 
140
        escape (x:xs) = x:escape xs
 
141
 
 
142
rulesForHappy :: CF -> Rules
 
143
rulesForHappy cf = map mkOne $ ruleGroups cf where
 
144
  mkOne (cat,rules) = constructRule cf rules cat
 
145
 
 
146
-- For every non-terminal, we construct a set of rules. A rule is a sequence of
 
147
-- terminals and non-terminals, and an action to be performed
 
148
-- As an optimization, a pair of list rules [C] ::= "" | C k [C]
 
149
-- is left-recursivized into [C] ::= "" | [C] C k.
 
150
-- This could be generalized to cover other forms of list rules.
 
151
constructRule :: CF -> [Rule] -> NonTerminal -> (NonTerminal,[(Pattern,Action)])
 
152
constructRule cf rules nt = (nt,[(p,generateAction nt (revF b r) m) | 
 
153
     r0 <- rules,
 
154
     let (b,r) = if isConsFun (funRule r0) && elem (valCat r0) revs 
 
155
                   then (True,revSepListRule r0) 
 
156
                 else (False,r0),
 
157
     let (p,m) = generatePatterns cf r])
 
158
 where
 
159
   revF b r = if b then ("flip " ++ funRule r) else (underscore $ funRule r)
 
160
   revs = reversibleCats cf
 
161
   underscore f | isDefinedRule f   = f ++ "_"
 
162
                | otherwise         = f
 
163
 
 
164
-- Generates a string containing the semantic action.
 
165
-- An action can for example be: Sum $1 $2, that is, construct an AST
 
166
-- with the constructor Sum applied to the two metavariables $1 and $2.
 
167
generateAction :: NonTerminal -> Fun -> [MetaVar] -> Action
 
168
generateAction nt f ms = unwords $ (if isCoercion f then [] else [f]) ++ ms
 
169
 
 
170
-- Generate patterns and a set of metavariables indicating 
 
171
-- where in the pattern the non-terminal
 
172
 
 
173
generatePatterns :: CF -> Rule -> (Pattern,[MetaVar])
 
174
generatePatterns cf r = case rhsRule r of
 
175
  []  -> ("{- empty -}",[])
 
176
  its -> (unwords (map mkIt its), metas its) 
 
177
 where
 
178
   mkIt i = case i of
 
179
     Left c -> identCat c
 
180
     Right s -> convert s
 
181
   metas its = [revIf c ('$': show i) | (i,Left c) <- zip [1 ::Int ..] its]
 
182
   revIf c m = if (not (isConsFun (funRule r)) && elem c revs) 
 
183
                 then ("(reverse " ++ m ++ ")") 
 
184
               else m  -- no reversal in the left-recursive Cons rule itself
 
185
   revs = reversibleCats cf
 
186
 
 
187
-- We have now constructed the patterns and actions, 
 
188
-- so the only thing left is to merge them into one string.
 
189
 
 
190
prRules :: Rules -> String
 
191
prRules = unlines . map prOne
 
192
  where
 
193
    prOne (nt,[]) = [] -- nt has only internal use
 
194
    prOne (nt,((p,a):ls)) =
 
195
      unwords [nt', "::", "{", normCat nt, "}\n" ++ 
 
196
               nt', ":" , p, "{", a, "}", "\n" ++ pr ls] ++ "\n"
 
197
     where 
 
198
       nt' = identCat nt
 
199
       pr [] = []
 
200
       pr ((p,a):ls) = 
 
201
         unlines [(concat $ intersperse " " ["  |", p, "{", a , "}"])] ++ pr ls
 
202
 
 
203
-- Finally, some haskell code.
 
204
 
 
205
finalize :: Bool -> CF -> String
 
206
finalize byteStrings cf = unlines $
 
207
   [
 
208
     "{",
 
209
     "\nreturnM :: a -> Err a",
 
210
     "returnM = return",
 
211
     "\nthenM :: Err a -> (a -> Err b) -> Err b",
 
212
     "thenM = (>>=)",
 
213
     "\nhappyError :: [" ++ tokenName ++ "] -> Err a",
 
214
     "happyError ts =", 
 
215
     "  Bad $ \"syntax error at \" ++ tokenPos ts ++ ",
 
216
     "  case ts of",
 
217
     "    [] -> []",
 
218
     "    [Err _] -> \" due to lexer error\"", 
 
219
     "    _ -> \" before \" ++ unwords (map ("++stringUnpack++" . prToken) (take 4 ts))",
 
220
     "",
 
221
     "myLexer = tokens"
 
222
   ] ++ definedRules cf ++ [ "}" ]
 
223
   where
 
224
     stringUnpack
 
225
       | byteStrings = "BS.unpack"
 
226
       | otherwise   = "id"
 
227
 
 
228
 
 
229
definedRules cf = [ mkDef f xs e | FunDef f xs e <- pragmasOfCF cf ]
 
230
    where
 
231
        mkDef f xs e = unwords $ (f ++ "_") : xs' ++ ["=", show e']
 
232
            where
 
233
                xs' = map (++"_") xs
 
234
                e'  = underscore e
 
235
        underscore (App x es)
 
236
            | isLower $ head x  = App (x ++ "_") $ map underscore es
 
237
            | otherwise         = App x $ map underscore es
 
238
        underscore e          = e
 
239
 
 
240
-- aarne's modifs 8/1/2002:
 
241
-- Markus's modifs 11/02/2002
 
242
 
 
243
-- GF literals
 
244
specialToks :: CF -> String
 
245
specialToks cf = unlines $
 
246
                 (map aux (literals cf))
 
247
                  ++ ["L_err    { _ }"]
 
248
 where aux cat = 
 
249
        case cat of
 
250
          "Ident"  -> "L_ident  { PT _ (TV $$) }"
 
251
          "String" -> "L_quoted { PT _ (TL $$) }"
 
252
          "Integer" -> "L_integ  { PT _ (TI $$) }"
 
253
          "Double" -> "L_doubl  { PT _ (TD $$) }"
 
254
          "Char"   -> "L_charac { PT _ (TC $$) }"
 
255
          own      -> "L_" ++ own ++ " { PT _ (T_" ++ own ++ " " ++ posn ++ ") }"
 
256
         where
 
257
           posn = if isPositionCat cf cat then "_" else "$$"
 
258
 
 
259
specialRules :: Bool -> CF -> String
 
260
specialRules byteStrings cf = unlines $
 
261
                  map aux (literals cf)
 
262
 where 
 
263
   aux cat = 
 
264
     case cat of
 
265
         "Ident"   -> "Ident   :: { Ident }   : L_ident  { Ident $1 }" 
 
266
         "String"  -> "String  :: { String }  : L_quoted { "++stringUnpack++" $1 }" 
 
267
         "Integer" -> "Integer :: { Integer } : L_integ  { (read ("++stringUnpack++" $1)) :: Integer }"
 
268
         "Double"  -> "Double  :: { Double }  : L_doubl  { (read ("++stringUnpack++" $1)) :: Double }"
 
269
         "Char"    -> "Char    :: { Char }    : L_charac { (read ("++stringUnpack++" $1)) :: Char }"
 
270
         own       -> own ++ "    :: { " ++ own ++ "} : L_" ++ own ++ " { " ++ own ++ " ("++ posn ++ "$1)}"
 
271
                -- PCC: take "own" as type name? (manual says newtype)
 
272
      where
 
273
         posn = if isPositionCat cf cat then "mkPosToken " else ""
 
274
 
 
275
   stringUnpack
 
276
     | byteStrings = "BS.unpack"
 
277
     | otherwise   = ""
 
278