packages feed

SableCC2Hs-0.0.0.1: src/SableCC/ParserDefinition.hs

----------------------------------------------------------------------------
-- |
-- Module      :  SableCC.ParserDefinition
-- Copyright   :  (c) Fontaine 2011
-- License     :  BSD3
--
-- Maintainer  :  fontaine@cs.uni-duesseldorf.de
-- Stability   :  experimental
-- Portability :  GHC-only
--
-- Highlevel definition of SableCC parser tables.
--
-----------------------------------------------------------------------------
{-# LANGUAGE GeneralizedNewtypeDeriving, RecordWildCards #-}
module SableCC.ParserDefinition
(
  makeParserDefinition
 ,ParserDefinition (..)
 ,trimTokens -- where to put this ?
)
where

import qualified SableCC.XML.ParserDefinitionRaw as Raw
import SableCC.XML.ParserDefinitionRaw hiding (Action)
import SableCC.ParserTypes

import Data.Array as Array
import Data.List as List
import Data.Map (Map)
import qualified Data.Map as Map
import Data.Maybe

data ParserDefinition = ParserDefinition {
   actionTable :: ActionTable
  ,gotoTable :: GotoTable
  ,errorTable :: Array ErrorID String
  ,initialStack :: [(ParserStateID, CST)]
  }

-- | Translate the low-level parser definition to a higher-level format
makeParserDefinition :: Raw.Parser -> ParserDefinition
makeParserDefinition rawParser = ParserDefinition {..}
  where
    actionTable = makeActionTable rawParser
    gotoTable   = makeGotoTable rawParser
    errorTable = mkArray ErrorID $ parser_error_messages
                   $ parser_parser_data rawParser
    initialStack = [(ParserStateID 0, error "dummy CST of initial parserStack")]

mkArray :: Ix i => (Int -> i) -> [e] -> Array i e
mkArray iType elems = listArray (iType 0, iType $ length elems -1 ) elems

makeGotoTable :: Raw.Parser -> GotoTable
makeGotoTable parser
  = mkArray GotoIndex $ map mkList $ parser_goto_table $ parser_parser_data parser
  where
    mkList ((-1,defaultVal):rest) = GotoMap {
       defaultGoto = ParserStateID defaultVal
      ,gotoMap = Map.fromList $ map (\(a,b) -> (ParserStateID a,ParserStateID b)) rest
      }
    mkList _ = error "mkList unexpected format in goto-list"

makeActionTable :: Raw.Parser -> ActionTable
makeActionTable rawParser
  = mkArray ParserStateID $ map mkTransitionList $ parser_action_table $ parser_parser_data rawParser
  where
    mkTransitionList :: [Raw.ParserAction] -> TransitionList
    mkTransitionList [] = error "empty transitionList"
    mkTransitionList (h:rest) = TransitionList {
       defaultTransition = snd $ mkTransition h
      ,transitionMap = Map.fromList $ map mkTransition rest
      }

    mkTransition :: Raw.ParserAction -> (ParserTokenID, Action)
    mkTransition Raw.ParserAction {..}
       = (,) (ParserTokenID action_from) $ case action_action of
          0 -> Shift $ ParserStateID action_to
          1 -> Reduce $ reductionTable ! action_to
          2 -> Accept
          3 -> Error $ ErrorID (errorIndirect ! action_to)

    reductionTable :: Array Int Reduction
    reductionTable = mkArray id $ map mkReduction $ parser_rules rawParser

    errorIndirect = mkArray id $ parser_errors $ parser_parser_data rawParser

    mkReduction :: Raw.Rule -> Reduction
    mkReduction rule = Reduction {
       reductionID = ReductionID $ rule_index rule
      ,popCount    = length $ filter isPopAction $ rule_actions rule
      ,gotoIndex   = GotoIndex $ rule_leftside rule
      }

trimTokens :: Raw.Parser -> [SToken] -> [PToken]
trimTokens rawParser tokens
  = mapMaybe translateToken tokens ++ [parserEof]
  where
    parserEof = (ParserTokenID $ parser_parser_eof_index rawParser,"")
    lexerTokens = mkArray LexTokenID $ parser_tokens rawParser
    translateToken (tokenID,str) = case token_parser_index (lexerTokens ! tokenID) of
      Nothing -> Nothing
      Just i -> Just (ParserTokenID i, str)