~ubuntu-branches/ubuntu/trusty/happy/trusty-proposed

« back to all changes in this revision

Viewing changes to src/Grammar.lhs

  • Committer: Bazaar Package Importer
  • Author(s): Ian Lynagh (wibble)
  • Date: 2006-10-26 22:52:14 UTC
  • mfrom: (1.2.2 upstream) (3.1.1 dapper)
  • Revision ID: james.westby@ubuntu.com-20061026225214-6jmf0n3ykkc9elyw
Tags: 1.16~rc2-1
* New upstream (release candidate) version.
* Removed happy/ prefixes from various paths in debian/rules and
  debian/docs.
* doc/configure generated by autoconf is in the Debian diff.
* Build using cabal:
  * Various debian/rules changes.
  * Create debian/get_version.hs for extracting the version from the cabal
    file.
  * Requires ghc6 >= 6.4.2.
  * No longer tries to detect platform. Closes: #340325, #332979.
  * Removed autotool-dev build-dep.
* Add 'XSLTPROC_OPTS = --nonet' to doc/config.mk.in.
* Remove src/Parser.ly and src/AttrGrammarParser.ly before cleaning so
  the generated files don't get cleaned.
* Set Standards-Version to 3.7.2 (no changes needed).
* Removed PS and DVI stanzas from debian/doc-base as we don't build
  the documentation those ways.
* Removed content-free postinst and prerm.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
-----------------------------------------------------------------------------
 
2
The Grammar data type.
 
3
 
 
4
(c) 1993-2001 Andy Gill, Simon Marlow
 
5
-----------------------------------------------------------------------------
 
6
 
 
7
Here is our mid-section datatype
 
8
 
 
9
> module Grammar (
 
10
>       Name, isEmpty, 
 
11
>       
 
12
>       Production, Grammar(..), mangler,
 
13
>       
 
14
>       LRAction(..), ActionTable, Goto(..), GotoTable, Priority(..),
 
15
>       Assoc(..),
 
16
>       
 
17
>       errorName, errorTok, startName, firstStartTok, dummyTok,
 
18
>       eofName, epsilonTok
 
19
>       ) where
 
20
 
 
21
> import GenUtils
 
22
> import AbsSyn
 
23
> import ParseMonad
 
24
> import AttrGrammar
 
25
> import AttrGrammarParser
 
26
 
 
27
> import Array
 
28
> import Char
 
29
> import List
 
30
> import Maybe (fromMaybe)
 
31
 
 
32
#ifdef DEBUG
 
33
 
 
34
> import IOExts
 
35
 
 
36
#endif
 
37
 
 
38
> type Name = Int
 
39
 
 
40
> type Production = (Name,[Name],(String,[Int]),Priority)
 
41
 
 
42
> data Grammar 
 
43
>       = Grammar {
 
44
>               productions       :: [Production],
 
45
>               lookupProdNo      :: Int -> Production,
 
46
>               lookupProdsOfName :: Name -> [Int],
 
47
>               token_specs       :: [(Name,String)],
 
48
>               terminals         :: [Name],
 
49
>               non_terminals     :: [Name],
 
50
>               starts            :: [(String,Name,Name,Bool)],
 
51
>               types             :: Array Int (Maybe String),
 
52
>               token_names       :: Array Int String,
 
53
>               first_nonterm     :: Name,
 
54
>               first_term        :: Name,
 
55
>               eof_term          :: Name,
 
56
>               priorities        :: [(Name,Priority)],
 
57
>               token_type        :: String,
 
58
>               imported_identity :: Bool,
 
59
>               monad             :: (Bool,String,String,String,String),
 
60
>               expect            :: Maybe Int,
 
61
>               attributes        :: [(String,String)],
 
62
>               attributetype     :: String,
 
63
>               lexer             :: Maybe (String,String),
 
64
>               error_handler     :: Maybe String
 
65
>       }
 
66
 
 
67
#ifdef DEBUG
 
68
 
 
69
> instance Show Grammar where
 
70
>       showsPrec _ (Grammar 
 
71
>               { productions           = p
 
72
>               , token_specs           = t
 
73
>               , terminals             = ts
 
74
>               , non_terminals         = nts
 
75
>               , starts                = starts
 
76
>               , types                 = tys
 
77
>               , token_names           = e
 
78
>               , first_nonterm         = fnt
 
79
>               , first_term            = ft
 
80
>               , eof_term              = eof
 
81
>               })
 
82
>        = showString "productions = "     . shows p
 
83
>        . showString "\ntoken_specs = "   . shows t
 
84
>        . showString "\nterminals = "     . shows ts
 
85
>        . showString "\nnonterminals = "  . shows nts
 
86
>        . showString "\nstarts = "        . shows starts
 
87
>        . showString "\ntypes = "         . shows tys
 
88
>        . showString "\ntoken_names = "   . shows e
 
89
>        . showString "\nfirst_nonterm = " . shows fnt
 
90
>        . showString "\nfirst_term = "    . shows ft
 
91
>        . showString "\neof = "           . shows eof
 
92
>        . showString "\n"
 
93
 
 
94
#endif
 
95
 
 
96
> data Assoc = LeftAssoc | RightAssoc | None
 
97
 
 
98
#ifdef DEBUG
 
99
 
 
100
>       deriving Show
 
101
 
 
102
#endif
 
103
 
 
104
> data Priority = No | Prio Assoc Int
 
105
 
 
106
#ifdef DEBUG
 
107
 
 
108
>       deriving Show
 
109
 
 
110
#endif
 
111
 
 
112
> instance Eq Priority where
 
113
>   No == No = True
 
114
>   Prio _ i == Prio _ j = i == j
 
115
>   _ == _ = False
 
116
 
 
117
> mkPrio :: Int -> Directive a -> Priority
 
118
> mkPrio i (TokenNonassoc _) = Prio None i
 
119
> mkPrio i (TokenRight _) = Prio RightAssoc i
 
120
> mkPrio i (TokenLeft _) = Prio LeftAssoc i
 
121
> mkPrio i _ = error "Panic: impossible case in mkPrio"
 
122
 
 
123
-----------------------------------------------------------------------------
 
124
-- Magic name values
 
125
 
 
126
All the tokens in the grammar are mapped onto integers, for speed.
 
127
The namespace is broken up as follows:
 
128
 
 
129
epsilon         = 0
 
130
error           = 1
 
131
dummy           = 2
 
132
%start          = 3..s
 
133
non-terminals   = s..n
 
134
terminals       = n..m
 
135
%eof            = m
 
136
 
 
137
These numbers are deeply magical, change at your own risk.  Several
 
138
other places rely on these being arranged as they are, including
 
139
ProduceCode.lhs and the various HappyTemplates.
 
140
 
 
141
Unfortunately this means you can't tell whether a given token is a
 
142
terminal or non-terminal without knowing the boundaries of the
 
143
namespace, which are kept in the Grammar structure.
 
144
 
 
145
In hindsight, this was probably a bad idea.
 
146
 
 
147
> startName = "%start" -- with a suffix, like %start_1, %start_2 etc.
 
148
> eofName   = "%eof"                    
 
149
> errorName = "error"
 
150
> dummyName = "%dummy"  -- shouldn't occur in the grammar anywhere
 
151
 
 
152
> firstStartTok, dummyTok, errorTok, epsilonTok :: Name
 
153
> firstStartTok   = 3
 
154
> dummyTok        = 2
 
155
> errorTok        = 1
 
156
> epsilonTok      = 0
 
157
 
 
158
> isEmpty :: Name -> Bool
 
159
> isEmpty n | n == epsilonTok = True
 
160
>           | otherwise       = False
 
161
 
 
162
-----------------------------------------------------------------------------
 
163
-- The Mangler
 
164
 
 
165
This bit is a real mess, mainly because of the error message support.
 
166
 
 
167
> m `thenE` k 
 
168
>       = case m of
 
169
>               Failed e    -> Failed e
 
170
>               Succeeded a -> case k a of
 
171
>                               Failed e -> Failed e
 
172
>                               Succeeded b -> Succeeded b
 
173
 
 
174
> m `parE` k 
 
175
>       = case m of
 
176
>               Failed e    -> case k (error "parE") of
 
177
>                               Failed e' -> Failed (e ++ e')
 
178
>                               Succeeded _ -> Failed e
 
179
>               Succeeded a -> case k a of
 
180
>                               Failed e -> Failed e
 
181
>                               Succeeded b -> Succeeded b
 
182
 
 
183
> parEs [] = Succeeded []
 
184
> parEs (x:xs) = x `parE` \x' ->
 
185
>                parEs xs `parE` \xs' ->
 
186
>                Succeeded (x':xs')
 
187
 
 
188
> failMap :: (b -> c) -> MaybeErr a [b] -> MaybeErr a [c]
 
189
> failMap f e = case e of
 
190
>                 Succeeded a -> Succeeded a
 
191
>                 Failed s -> Failed (map f s)
 
192
 
 
193
 
 
194
> mangler :: FilePath -> AbsSyn -> MaybeErr Grammar [String]
 
195
> mangler file (AbsSyn hd dirs rules tl) = 
 
196
 
 
197
>         -- add filename to all error messages
 
198
>       failMap (\s -> file ++ ": " ++ s) $
 
199
 
 
200
>       checkRules ([n | (n,_,_) <- rules]) "" [] `thenE` \nonterm_strs  ->
 
201
 
 
202
>       let
 
203
 
 
204
>       terminal_strs  = concat (map getTerm dirs) ++ [eofName]
 
205
 
 
206
>       n_starts   = length starts
 
207
>       n_nts      = length nonterm_strs
 
208
>       n_ts       = length terminal_strs
 
209
>       first_nt   = firstStartTok + n_starts
 
210
>       first_t    = first_nt + n_nts
 
211
>       last_start = first_nt - 1
 
212
>       last_nt    = first_t  - 1
 
213
>       last_t     = first_t + n_ts - 1
 
214
 
 
215
>       start_names    = [ firstStartTok .. last_start ]
 
216
>       nonterm_names  = [ first_nt .. last_nt ]
 
217
>       terminal_names = [ first_t .. last_t ]
 
218
 
 
219
>       starts      = case getParserNames dirs of
 
220
>                       [] -> [TokenName "happyParse" Nothing False]
 
221
>                       ns -> ns
 
222
>
 
223
>       start_strs  = [ startName++'_':p  | (TokenName p _ _) <- starts ]
 
224
 
 
225
Build up a mapping from name values to strings.
 
226
 
 
227
>       name_env = (errorTok, errorName) :
 
228
>                  (dummyTok, dummyName) :
 
229
>                  zip start_names    start_strs ++
 
230
>                  zip nonterm_names  nonterm_strs ++
 
231
>                  zip terminal_names terminal_strs
 
232
 
 
233
>       lookupName :: String -> [Name]
 
234
>       lookupName n = [ t | (t,r) <- name_env, r == n ]
 
235
 
 
236
>       mapToName str = 
 
237
>             case lookupName str  of
 
238
>                [a] -> Succeeded a
 
239
>                []  -> Failed ["unknown identifier `" ++ str ++ "'"]
 
240
>                _   -> Failed ["multiple use of `" ++ str ++ "'"]
 
241
 
 
242
Start symbols...
 
243
 
 
244
>               -- default start token is the first non-terminal in the grammar
 
245
>       lookupStart (TokenName s Nothing  _) = Succeeded first_nt
 
246
>       lookupStart (TokenName s (Just n) _) = mapToName n
 
247
>       in
 
248
 
 
249
>       parEs (map lookupStart starts)  `thenE` \ start_toks ->
 
250
 
 
251
>       let
 
252
>       parser_names   = [ s | TokenName s _ _ <- starts ]
 
253
>       start_partials = [ b | TokenName _ _ b <- starts ]
 
254
>       start_prods = zipWith (\nm tok -> (nm, [tok], ("no code",[]), No))
 
255
>                        start_names start_toks
 
256
 
 
257
Deal with priorities...
 
258
 
 
259
>       priodir = zip [1..] (getPrios dirs)
 
260
>
 
261
>       prios = [ (name,mkPrio i dir)
 
262
>               | (i,dir) <- priodir
 
263
>               , nm <- AbsSyn.getPrioNames dir
 
264
>               , name <- lookupName nm
 
265
>               ]
 
266
 
 
267
>       prioByString = [ (name, mkPrio i dir)
 
268
>                      | (i,dir) <- priodir
 
269
>                      , name <- AbsSyn.getPrioNames dir
 
270
>                      ]
 
271
 
 
272
Translate the rules from string to name-based.
 
273
 
 
274
>       convNT (nt, prods, ty) 
 
275
>         = mapToName nt `thenE` \nt' ->
 
276
>           Succeeded (nt', prods, ty)
 
277
>
 
278
>       attrs = getAttributes dirs
 
279
>       attrType = fromMaybe "HappyAttrs" (getAttributetype dirs)
 
280
>
 
281
>       transRule (nt, prods, ty)
 
282
>         = parEs (map (finishRule nt) prods)
 
283
>
 
284
>       finishRule nt (lhs,code,line,prec)
 
285
>         = failMap (addLine line) $
 
286
>          parEs (map mapToName lhs)   `parE`  \lhs' ->
 
287
>          checkCode (length lhs) lhs' nonterm_names code attrs `thenE`  \code' ->
 
288
>           case mkPrec lhs' prec of
 
289
>               Left s  -> Failed ["Undeclared precedence token: " ++ s]
 
290
>               Right p -> Succeeded (nt, lhs', code', p)
 
291
>
 
292
>       mkPrec :: [Name] -> Maybe String -> Either String Priority
 
293
>       mkPrec lhs prio =
 
294
>             case prio of
 
295
>               Nothing -> case filter (flip elem terminal_names) lhs of
 
296
>                            [] -> Right No
 
297
>                            xs -> case lookup (last xs) prios of
 
298
>                                    Nothing -> Right No
 
299
>                                    Just p  -> Right p
 
300
>               Just s -> case lookup s prioByString of
 
301
>                           Nothing -> Left s
 
302
>                           Just p -> Right p
 
303
>       in
 
304
 
 
305
>       parEs (map convNT rules)    `thenE` \rules1 ->
 
306
>       parEs (map transRule rules1) `thenE` \rules2 ->
 
307
 
 
308
>       let
 
309
>       tys = accumArray (\a b -> b) Nothing (first_nt, last_nt) 
 
310
>                       [ (nm, Just ty) | (nm, _, Just ty) <- rules1 ]
 
311
 
 
312
>       env_array :: Array Int String
 
313
>       env_array = array (errorTok, last_t) name_env
 
314
>       in
 
315
 
 
316
Get the token specs in terms of Names.
 
317
 
 
318
>       let 
 
319
>       fixTokenSpec (a,b) = mapToName a `thenE` \a -> Succeeded (a,b)
 
320
>       in
 
321
>       parEs (map fixTokenSpec (getTokenSpec dirs)) `thenE` \tokspec ->
 
322
 
 
323
>       let
 
324
>          ass = combinePairs [ (a,no)
 
325
>                             | ((a,_,_,_),no) <- zip productions [0..] ]
 
326
>          arr = array (firstStartTok, length ass - 1 + firstStartTok) ass
 
327
 
 
328
>          lookup_prods :: Name -> [Int]
 
329
>          lookup_prods x | x >= firstStartTok && x < first_t = arr ! x
 
330
>          lookup_prods _ = error "lookup_prods"
 
331
>
 
332
>          productions = start_prods ++ concat rules2
 
333
>          prod_array  = listArray' (0,length productions-1) productions
 
334
>       in
 
335
 
 
336
>       Succeeded (Grammar {
 
337
>               productions       = productions,
 
338
>               lookupProdNo      = (prod_array !),
 
339
>               lookupProdsOfName = lookup_prods,
 
340
>               token_specs       = tokspec,
 
341
>               terminals         = errorTok : terminal_names,
 
342
>               non_terminals     = start_names ++ nonterm_names,
 
343
>                                       -- INCLUDES the %start tokens
 
344
>               starts            = zip4 parser_names start_names start_toks
 
345
>                                       start_partials,
 
346
>               types             = tys,
 
347
>               token_names       = env_array,
 
348
>               first_nonterm     = first_nt,
 
349
>               first_term        = first_t,
 
350
>               eof_term          = last terminal_names,
 
351
>               priorities        = prios,
 
352
>               imported_identity                 = getImportedIdentity dirs,
 
353
>               monad             = getMonad dirs,
 
354
>               lexer             = getLexer dirs,
 
355
>               error_handler     = getError dirs,
 
356
>               token_type        = getTokenType dirs,
 
357
>               expect            = getExpect dirs,
 
358
>               attributes        = attrs,
 
359
>               attributetype     = attrType
 
360
>       })
 
361
 
 
362
For combining actions with possible error messages.
 
363
 
 
364
> addLine :: Int -> String -> String
 
365
> addLine l s = show l ++ ": " ++ s
 
366
 
 
367
> getTerm (TokenSpec stuff) = map fst stuff
 
368
> getTerm _                 = []
 
369
 
 
370
So is this.
 
371
 
 
372
> checkRules (name:rest) above nonterms
 
373
>       | name == above = checkRules rest name nonterms
 
374
>       | name `elem` nonterms 
 
375
>               = Failed ["Multiple rules for `" ++ name ++ "'"]
 
376
>       | otherwise = checkRules rest name (name : nonterms)
 
377
 
 
378
> checkRules [] _ nonterms = Succeeded (reverse nonterms)
 
379
 
 
380
 
 
381
-----------------------------------------------------------------------------
 
382
-- If any attribute directives were used, we are in an attribute grammar, so
 
383
-- go do special processing.  If not, pass on to the regular processing routine
 
384
 
 
385
> checkCode :: Int -> [Name] -> [Name] -> String -> [(String,String)] -> MaybeErr (String,[Int]) [String]
 
386
> checkCode arity lhs nonterm_names code []    = doCheckCode arity code
 
387
> checkCode arity lhs nonterm_names code attrs = rewriteAttributeGrammar arity lhs nonterm_names code attrs
 
388
 
 
389
------------------------------------------------------------------------------
 
390
-- Special processing for attribute grammars.  We re-parse the body of the code
 
391
-- block and output the nasty-looking record manipulation and let binding goop
 
392
--
 
393
 
 
394
> rewriteAttributeGrammar :: Int -> [Name] -> [Name] -> String -> [(String,String)] -> MaybeErr (String,[Int]) [String]
 
395
> rewriteAttributeGrammar arity lhs nonterm_names code attrs =
 
396
 
 
397
   first we need to parse the body of the code block
 
398
 
 
399
>     case runP agParser code 0 of
 
400
>        FailP msg  -> Failed [ "error in attribute grammar rules: "++msg ]
 
401
>        OkP rules  ->
 
402
 
 
403
   now we break the rules into three lists, one for synthesized attributes,
 
404
   one for inherited attributes, and one for conditionals
 
405
 
 
406
>            let (selfRules,subRules,conditions) = partitionRules [] [] [] rules
 
407
>                attrNames = map fst attrs
 
408
>                defaultAttr = head attrNames
 
409
 
 
410
   now check that $i references are in range
 
411
 
 
412
>            in parEs (map checkArity (mentionedProductions rules)) `thenE` \prods -> 
 
413
 
 
414
   and output the rules
 
415
 
 
416
>                formatRules arity attrNames defaultAttr 
 
417
>                            allSubProductions selfRules 
 
418
>                            subRules conditions `thenE` \rulesStr ->
 
419
 
 
420
   return the munged code body and all sub-productions mentioned
 
421
 
 
422
>               Succeeded (rulesStr,nub (allSubProductions++prods))
 
423
 
 
424
 
 
425
>    where partitionRules a b c [] = (a,b,c)
 
426
>          partitionRules a b c (RightmostAssign attr toks : xs) = partitionRules a (SubAssign (arity,attr) toks : b) c xs
 
427
>          partitionRules a b c (x@(SelfAssign _ _ )  : xs) = partitionRules (x:a) b c xs
 
428
>          partitionRules a b c (x@(SubAssign _ _)    : xs) = partitionRules a (x:b) c xs
 
429
>          partitionRules a b c (x@(Conditional _)    : xs) = partitionRules a b (x:c) xs
 
430
 
 
431
>          allSubProductions             = map (+1) (findIndices (`elem` nonterm_names) lhs)
 
432
 
 
433
>          mentionedProductions rules    = [ i | (AgTok_SubRef (i,_)) <- concat (map getTokens rules) ]
 
434
 
 
435
>          getTokens (SelfAssign _ toks)      = toks
 
436
>          getTokens (SubAssign _ toks)       = toks
 
437
>          getTokens (Conditional toks)       = toks
 
438
>          getTokens (RightmostAssign _ toks) = toks
 
439
>           
 
440
>          checkArity x = if x <= arity then Succeeded x else Failed [show x++" out of range"]
 
441
 
 
442
 
 
443
 
 
444
------------------------------------------------------------------------------------
 
445
-- Actually emit the code for the record bindings and conditionals
 
446
--
 
447
 
 
448
> formatRules :: Int -> [String] -> String -> [Name] 
 
449
>             -> [AgRule] -> [AgRule] -> [AgRule] 
 
450
>             -> MaybeErr String [String]
 
451
 
 
452
> formatRules arity attrNames defaultAttr prods selfRules subRules conditions = Succeeded $
 
453
>     concat [ "\\happyInhAttrs -> let { "
 
454
>            , "happySelfAttrs = happyInhAttrs",formattedSelfRules
 
455
>            , subProductionRules
 
456
>            , "; happyConditions = ", formattedConditions
 
457
>            , " } in (happyConditions,happySelfAttrs)"
 
458
>            ]
 
459
>
 
460
>  where formattedSelfRules = case selfRules of [] -> []; _ -> "{ "++formattedSelfRules'++" }"
 
461
>        formattedSelfRules' = concat $ intersperse ", " $ map formatSelfRule selfRules
 
462
>        formatSelfRule (SelfAssign [] toks)   = defaultAttr++" = "++(formatTokens toks)
 
463
>        formatSelfRule (SelfAssign attr toks) = attr++" = "++(formatTokens toks)
 
464
 
 
465
>        subRulesMap :: [(Int,[(String,[AgToken])])]
 
466
>        subRulesMap = map     (\l   -> foldr (\ (_,x) (i,xs) -> (i,x:xs))
 
467
>                                             (fst $ head l,[snd $ head l])
 
468
>                                             (tail l) ) .
 
469
>                      groupBy (\x y -> (fst x) == (fst y)) .
 
470
>                      sortBy  (\x y -> compare (fst x) (fst y)) .
 
471
>                      map     (\(SubAssign (i,id) toks) -> (i,(id,toks))) $ subRules
 
472
 
 
473
>        subProductionRules = concat $ map formatSubRules prods
 
474
 
 
475
>        formatSubRules i = 
 
476
>           let attrs = fromMaybe [] . lookup i $ subRulesMap
 
477
>               attrUpdates' = concat $ intersperse ", " $ map (formatSubRule i) attrs
 
478
>               attrUpdates  = case attrUpdates' of [] -> []; x -> "{ "++x++" }"
 
479
>           in concat ["; (happyConditions_",show i,",happySubAttrs_",show i,") = ",mkHappyVar i
 
480
>                     ," happyEmptyAttrs"
 
481
>                     , attrUpdates
 
482
>                     ]
 
483
>         
 
484
>        formattedConditions = concat $ intersperse "++" $ localConditions : (map (\i -> "happyConditions_"++(show i)) prods)
 
485
>        localConditions = "["++(concat $ intersperse ", " $ map formatCondition conditions)++"]"
 
486
>        formatCondition (Conditional toks) = formatTokens toks
 
487
 
 
488
>        formatSubRule i ([],toks)   = defaultAttr++" = "++(formatTokens toks)
 
489
>        formatSubRule i (attr,toks) = attr++" = "++(formatTokens toks)
 
490
 
 
491
>        formatTokens tokens = concat (map formatToken tokens)
 
492
 
 
493
>        formatToken AgTok_LBrace           =  "{ "
 
494
>        formatToken AgTok_RBrace           = "} "
 
495
>        formatToken AgTok_Where            = "where "
 
496
>        formatToken AgTok_Semicolon        = "; "
 
497
>        formatToken AgTok_Eq               = "="
 
498
>        formatToken (AgTok_SelfRef [])     = "("++defaultAttr++" happySelfAttrs) "
 
499
>        formatToken (AgTok_SelfRef x)      = "("++x++" happySelfAttrs) "
 
500
>        formatToken (AgTok_RightmostRef x) = formatToken (AgTok_SubRef (arity,x))
 
501
>        formatToken (AgTok_SubRef (i,[])) 
 
502
>            | i `elem` prods = "("++defaultAttr++" happySubAttrs_"++(show i)++") "
 
503
>            | otherwise      = mkHappyVar i ++ " "
 
504
>        formatToken (AgTok_SubRef (i,x)) 
 
505
>            | i `elem` prods = "("++x++" happySubAttrs_"++(show i)++") "
 
506
>            | otherwise      = error "lhs "++(show i)++" is not a non-terminal"
 
507
>        formatToken (AgTok_Unknown x)     = x++" "
 
508
 
 
509
 
 
510
-----------------------------------------------------------------------------
 
511
-- Check for every $i that i is <= the arity of the rule.
 
512
 
 
513
-- At the same time, we collect a list of the variables actually used in this
 
514
-- code, which is used by the backend.
 
515
 
 
516
> doCheckCode :: Int -> String -> MaybeErr (String, [Int]) [String]
 
517
> doCheckCode arity code = go code "" []
 
518
>   where go code acc used =
 
519
>           case code of
 
520
>               [] -> Succeeded (reverse acc, used)
 
521
>       
 
522
>               '"'  :r    -> case reads code :: [(String,String)] of
 
523
>                                []      -> go r ('"':acc) used
 
524
>                                (s,r):_ -> go r (reverse (show s) ++ acc) used
 
525
>               a:'\'' :r | isAlphaNum a -> go r ('\'':a:acc) used
 
526
>               '\'' :r    -> case reads code :: [(Char,String)] of
 
527
>                                []      -> go r ('\'':acc) used
 
528
>                                (c,r):_ -> go r (reverse (show c) ++ acc) used
 
529
>               '\\':'$':r -> go r ('$':acc) used
 
530
>
 
531
>               '$':'>':r -- the "rightmost token"
 
532
>                       | arity == 0 -> Failed [ "$> in empty rule" ] 
 
533
>                       | otherwise  -> go r (reverse (mkHappyVar arity) ++ acc)
 
534
>                                        (arity : used)
 
535
>
 
536
>               '$':r@(i:_) | isDigit i -> 
 
537
>                       case reads r :: [(Int,String)] of
 
538
>                         (j,r):_ -> 
 
539
>                            if j > arity 
 
540
>                                 then Failed [ '$': show j ++ " out of range" ] 
 
541
>                                       `parE` \_ -> go r acc used
 
542
>                                 else go r (reverse (mkHappyVar j) ++ acc) 
 
543
>                                        (j : used)
 
544
>                         
 
545
>               c:r  -> go r (c:acc) used
 
546
 
 
547
> mkHappyVar n  = "happy_var_" ++ show n
 
548
 
 
549
-----------------------------------------------------------------------------
 
550
-- Internal Reduction Datatypes
 
551
 
 
552
> data LRAction = LR'Shift Int Priority -- state number and priority
 
553
>               | LR'Reduce Int Priority-- rule no and priority
 
554
>               | LR'Accept             -- :-)
 
555
>               | LR'Fail               -- :-(
 
556
>               | LR'MustFail           -- :-(
 
557
>               | LR'Multiple [LRAction] LRAction       -- conflict
 
558
>       deriving(Eq
 
559
 
 
560
#ifdef DEBUG
 
561
 
 
562
>       ,Show
 
563
 
 
564
#endif
 
565
 
 
566
>       )       
 
567
 
 
568
> type ActionTable = Array Int{-state-} (Array Int{-terminal#-} LRAction)
 
569
 
 
570
 instance Text LRAction where 
 
571
   showsPrec _ (LR'Shift i _)  = showString ("s" ++ show i)
 
572
   showsPrec _ (LR'Reduce i _) 
 
573
       = showString ("r" ++ show i)
 
574
   showsPrec _ (LR'Accept)     = showString ("acc")
 
575
   showsPrec _ (LR'Fail)       = showString (" ")
 
576
 instance Eq LRAction where { (==) = primGenericEq } 
 
577
 
 
578
> data Goto = Goto Int | NoGoto 
 
579
>       deriving(Eq
 
580
 
 
581
#ifdef DEBUG
 
582
 
 
583
>       ,Show
 
584
 
 
585
#endif
 
586
 
 
587
>       )       
 
588
 
 
589
> type GotoTable = Array Int{-state-} (Array Int{-nonterminal #-} Goto)