我如何有效地使用Alex的启动代码功能?

我开始学习Alex并相信我已经到了有状态的环境会有所帮助的地步,但我并不完全知道如何去做。 我试图从erlang二进制文件的有限子集中提取出来。 通过以下词法分析器:

{
module Main (main, Token(..), AlexPosn(..), alexScanTokens, token_posn) where
}

%wrapper "posn"

$digit = 0-9      -- digits                                                                            
$alpha = [a-zA-Z] -- alphabetic characters                                                             
$dbl_quote = "

tokens :-

  $white+                        ;
  ","                            { tok (p s -> Comma p) }
  "<<"                           { tok (p s -> BinaryOpen p) }
  ">>"                           { tok (p s -> BinaryClose p) }
  $dbl_quote [^$dbl_quote]* $dbl_quote { tok (p s -> ErlStr p (init (tail s))) }
  $digit+                        { tok (p s -> ErlInt p (read s)) }

{
-- action helpers:                                                                                     
tok :: (AlexPosn -> String -> Token) -> AlexPosn -> String -> Token
tok f p s = f p s

data Token =
  Comma       AlexPosn |
  BinaryOpen  AlexPosn |
  BinaryClose AlexPosn |
  ErlInt   AlexPosn Integer |
  ErlStr   AlexPosn String
  deriving (Eq, Show)

token_posn :: Token -> AlexPosn
token_posn (Comma    p) = p
token_posn (BinaryOpen  p) = p
token_posn (BinaryClose p) = p
token_posn (ErlInt   p _) = p
token_posn (ErlStr   p _) = p

main :: IO ()
main = do
  s <- getContents
  print (alexScanTokens s)
}

我做得很好。 例如,

> alex so_erlang_lexer.x  && ghc --make -o erlexer so_erlang_lexer.hs && echo '<<"100", 1>>' | ./erlexer 
[1 of 1] Compiling Main             ( so_erlang_lexer.hs, so_erlang_lexer.o )
Linking erlexer ...
[BinaryOpen (AlexPn 0 1 1),ErlStr (AlexPn 2 1 3) "100",Comma (AlexPn 7 1 8),ErlInt (AlexPn 9 1 10) 1,BinaryClose (AlexPn 10 1 11)]

我宁愿让lexed返回等价于Binary [ErlStr "100", ErlInt 1] ,但我一直没能找到一个使用开始代码的词法分析器,该代码在我的脑海中点击。

  • 这里引用的GHC的词法分析器不使用任何Alex包装器。
  • Alex自己的monad和monadUserState包装文档让我不能确定应该选择哪一种,以及如何使用它们。
  • 亚历克斯老虎的榜样是最有希望的,但它太大了,我无法清除我的无知。
  • 这个问题使用monad解析器,但似乎没有使用它的状态特性。
  • 有人会如此善良引导我一点吗?


    我不完全确定你正在试图用词法分析器做什么,并且知道足以引导你对此(但如果你需要的只是过滤器无用的标记,亚历克斯的monadic界面似乎是一种矫枉过正),无论如何,这里有一个示例代码来使用AlexUserState使用“monadUserState”包装器累积选定的标记。

    
    
    {
    module Main (main) where
    }
    
    %wrapper "monadUserState"
    
    $digit = 0-9      -- digits                                                                            
    $alpha = [a-zA-Z] -- alphabetic characters                                                             
    $dbl_quote = "
    
    tokens :-
    
      $white+                              ;
      ","                                  { ignoreToken  }
      ">"                                 { ignoreToken }
      $dbl_quote [^$dbl_quote]* $dbl_quote { pushToken  $ ErlStr . init . tail  }
      $digit+                              { pushToken  $ ErlInt . read }
    
    {
    
    alexEOF :: Alex ()
    alexEOF = return ()
    
    -- some useful interaces to the Alex monad (which is naturally an instance of state monad)
    modifyUserState :: (AlexUserState -> AlexUserState) -> Alex ()
    modifyUserState f = Alex (s -> let st = alex_ust s in Right (s {alex_ust = f st},()))
    
    getUserState ::  Alex AlexUserState
    getUserState = Alex (s -> Right (s,alex_ust s))
    
    -- Token definition minus position information for simplicity
    data Token =
      Comma        |
      BinaryOpen   |
      BinaryClose  |
      ErlInt    Integer |
      ErlStr    String
      deriving (Eq, Show)
    
    newtype AlexUserState = Binary [Token]
      deriving (Eq, Show)
    
    alexInitUserState :: AlexUserState
    alexInitUserState = Binary []
    
    
    -- action helpers:                                                                                     
    pushToken :: (String -> Token) -> AlexAction ()
    pushToken tokenizer = 
      (posn,prevChar,pending,s) len -> modifyUserState (push $ take len s) >> alexMonadScan
        where
           -- Here tokens are accumulated in reverse order for efficiency.
           -- You need a more powerful data structure like Data.Sequence to preserve the order.
           push :: String -> AlexUserState -> AlexUserState
           push s (Binary ts) = Binary (tokenizer s : ts) 
    
    ignoreToken :: AlexAction ()
    ignoreToken _ _   = alexMonadScan
    
    
    runAlexScan :: String -> Either String AlexUserState
    runAlexScan s = runAlex s $ alexMonadScan >> getUserState
    
    
    main :: IO ()
    main = getContents >>= print . runAlexScan
    
    }
    
    

    但我想主要的问题是,你似乎还没有熟悉Haskell中单子的概念和用法。 Alex的monadic接口实际上是非常自然且典型的状态monad,一旦你有了一些编码实验,只需简单地浏览生成的代码就可以轻松猜出。 (如果你猜错了,类型检查器很可能会发现相关错误。)

    为此,因为在这里似乎有许多关于monads的很好的问题和答案,所以我只提到Real World Haskell(关于分析的章节对我来说特别有用)。

    但是如果你碰巧已经有了分类理论的知识,可能最快的学习单子的方法是直接在相关的论文中进行探究(并且请记住,类别理论中的单子是行动的一般化,就像团体的行动一样)自然适合编程环境。)为此,请参阅关于单子和箭头的文章列表,其中包括针对具有某些技术背景的人员的入门论文和教程。

    顺便说一句,我刚开始学习Erlang。 你能不能指导我一点呢? 有没有缺乏静态打字咬你? 你有没有试过cloud-haskell,并将它与Erlang进行比较? 在分布式编程环境下,您认为哪种语言最有成效?

    链接地址: http://www.djcxy.com/p/11241.html

    上一篇: How can I effectively use the start code features of Alex?

    下一篇: Partially denormalising unicorn observations