Difference between revisions of "Alex/Wrapper monadUser"

From HaskellWiki
Jump to navigation Jump to search
(Add notes for wrapper for alex)
 
(Add explanation of wrapper)
 
Line 1: Line 1:
  +
==What are we trying to solve?==
  +
Often, when lexing files, some form of '''state''' is desired. This could be as simple as a '''depth count''' in nested comments, or more complex such as a list of files already imported.
  +
  +
See [[Alex/Wrapper monadUser#Solution details |the details below]] for more information.
  +
 
==The file==
 
==The file==
   
Line 28: Line 33:
   
 
To be done once the UofCalgary 411 class is done their first assignment :) [[User:BrettGiles|BrettGiles]]
 
To be done once the UofCalgary 411 class is done their first assignment :) [[User:BrettGiles|BrettGiles]]
  +
  +
==Solution details==
  +
===The problem===
  +
As mentioned above, we want some form of '''state'' when lexing.
  +
  +
However, other than writing your own state managment, or using the somewhat complicated <code>gscan</code> wrapper, there is no convenient way to manage this state. The current <code>monad</code> wrapper only provides a limited set of state items, including the last character, the upcoming string, the current start code and the current position.
  +
===The solution===
  +
  +
Starting from the <code>monad</code> wrapper, we add a few simple items. First, to the <hask>AlexState</hask> type used in that wrapper, we add an item of type <hask>UserState</hask>, giving us:
  +
<haskell>
  +
data AlexState = AlexState {
  +
alex_pos :: !AlexPosn, -- position at current input location
  +
alex_inp :: String, -- the current input
  +
alex_chr :: !Char, -- the character before the input
  +
alex_scd :: !Int, -- the current startcode
  +
alex_usr :: !UserState -- User data
  +
}
  +
</haskell>
  +
  +
Then, to the definition of the function <hask>runAlex</hask>, we add a starting value for the <hask>UserState</hask>:
  +
<haskell>
  +
runAlex :: String -> Alex a -> Either String a
  +
runAlex input (Alex f)
  +
= case f (AlexState {alex_pos = alexStartPos,
  +
alex_inp = input,
  +
alex_chr = '\n',
  +
alex_scd = 0,
  +
alex_usr = userStartState}) of Left msg -> Left msg
  +
Right ( _, a ) -> Right a
  +
</haskell>
  +
  +
This requires the user to define the type and start value in the alex file.

Latest revision as of 21:21, 1 February 2007

What are we trying to solve?

Often, when lexing files, some form of state is desired. This could be as simple as a depth count in nested comments, or more complex such as a list of files already imported.

See the details below for more information.

The file

Download the code: media:AlexWrapper-monadUser

Note this is only a minor change to the current monad wrapper.

Usage

In the Alex source file

In Alex, wrappers are chosen by the %wrapper directive. To use the monadUser wrapper, add the line

    %wrapper "monadUser"

after the initial code block in your Alex source file.

Additionally, two items must be defined in a code block (or imported), the Haskell type UserData and the variable userStartState which must be of type UserData.

Where to put the wrapper source file

Alex retrieves wrappers from its template directory, typically /usr/lib/alex2.x.x. If you have access to that directory, simply place the file in there.

If not, create a directory named alex in your home directory. Copy all of the files from /usr/lib/alex2.x.x to alex. Then place the downloaded file in that directory.

Then, when running Alex, use the command:

   alex -t ~/alex input.x

which will tell alex to use the new directory for its templates.

Examples of use

To be done once the UofCalgary 411 class is done their first assignment :) BrettGiles

Solution details

The problem

As mentioned above, we want some form of 'state when lexing.

However, other than writing your own state managment, or using the somewhat complicated gscan wrapper, there is no convenient way to manage this state. The current monad wrapper only provides a limited set of state items, including the last character, the upcoming string, the current start code and the current position.

The solution

Starting from the monad wrapper, we add a few simple items. First, to the AlexState type used in that wrapper, we add an item of type UserState, giving us:

data AlexState = AlexState {
	alex_pos :: !AlexPosn,	-- position at current input location
	alex_inp :: String,	-- the current input
	alex_chr :: !Char,	-- the character before the input
	alex_scd :: !Int, 	-- the current startcode
        alex_usr :: !UserState      -- User data
    }

Then, to the definition of the function runAlex, we add a starting value for the UserState:

runAlex :: String -> Alex a -> Either String a
runAlex input (Alex f) 
   = case f (AlexState {alex_pos = alexStartPos,
 			alex_inp = input,	
			alex_chr = '\n',
			alex_scd = 0,
                        alex_usr = userStartState}) of Left msg -> Left msg
				                       Right ( _, a ) -> Right a

This requires the user to define the type and start value in the alex file.