Created
June 30, 2016 02:32
-
-
Save m1dnight/126d6b500175c2c286e3804584e5c4ce to your computer and use it in GitHub Desktop.
Monadic Parser and Lexer using Alex and Happy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
module Lexer where | |
} | |
%wrapper "monadUserState" | |
$digit = 0-9 -- digits | |
$alpha = [a-zA-Z] -- alphabetic characters | |
-- Each token has a function on the RHS that is a function (String -> | |
-- Token). We wrap this function in the Alex monad with `pushToken`, which has | |
-- a result AlexAction (). | |
tokens :- | |
$white+ ; | |
$alpha+ { pushToken $ TString } | |
$digit+ { pushToken $ TNumber . read } | |
'@' { pushToken $ \_ -> TAt } | |
{ | |
------------ | |
-- Tokens -- | |
------------ | |
data Token | |
= TNumber Integer | |
| TString String | |
| TAt | |
deriving (Show, Eq) | |
----------- | |
-- Types -- | |
----------- | |
type AlexUserState = [Token] | |
type ParseError = String | |
-------------------- | |
-- Parser Helpers -- | |
-------------------- | |
alexEOF :: Alex () | |
alexEOF = return () | |
ignore input len = alexMonadScan | |
----------------- | |
-- Lexer State -- | |
----------------- | |
alexInitUserState :: AlexUserState | |
alexInitUserState = [] | |
modifyUserState :: (AlexUserState -> AlexUserState) -> Alex () | |
modifyUserState f = Alex $ \s -> let current = alex_ust s | |
new = f current | |
in | |
Right (s { alex_ust = new },()) | |
getUserState :: Alex AlexUserState | |
getUserState = Alex $ \s -> Right (s,alex_ust s) | |
pushToken :: (String -> Token) -> AlexAction () | |
pushToken tokenizer = | |
\(posn,prevChar,pending,s) len -> modifyUserState (push $ take len s) >> alexMonadScan | |
where | |
push :: String -> AlexUserState -> AlexUserState | |
push s ts = ts ++ [(tokenizer s)] | |
runAlexScan :: String -> Either ParseError AlexUserState | |
runAlexScan s = runAlex s $ alexMonadScan >> getUserState | |
--main = getContents >>= print . runAlexScan | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
module Parser where | |
import Lexer | |
import Syntax | |
import Text.Printf | |
} | |
%name calc | |
%tokentype { Token } | |
%error { parseError } | |
%monad{ Either String }{ >>= }{ return } | |
%token | |
'@' { TAt } | |
number { TNumber $$ } | |
var { TString $$ } | |
%% | |
AST | |
: '@' { At } | |
| number { Numbr $1 } | |
| var { Name $1 } | |
{ | |
parseError ts = fail "Parse error" | |
parse :: String -> Either ParseError AST | |
parse input = runAlexScan input >>= calc | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Syntax where | |
data AST | |
= Numbr Integer | |
| Name String | |
| At | |
deriving (Show, Eq) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment