Skip to content

Commit

Permalink
Refactor First set computation
Browse files Browse the repository at this point in the history
  • Loading branch information
Kariiem authored and sgraf812 committed Oct 7, 2024
1 parent dc05342 commit c31a401
Showing 1 changed file with 23 additions and 22 deletions.
45 changes: 23 additions & 22 deletions lib/tabular/src/Happy/Tabular/First.lhs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Implementation of FIRST
> import Happy.Tabular.NameSet ( NameSet )
> import qualified Happy.Tabular.NameSet as Set
> import Happy.Grammar
> import Data.Maybe (fromMaybe)

\subsection{Utilities}

Expand All @@ -20,15 +21,13 @@ Implementation of FIRST
> | otherwise = h

@mkClosure@ makes a closure, when given a comparison and iteration loop.
It's a fixed point computation, we keep applying the function over the
input until it does not change.
Be careful, because if the functional always makes the object different,
This will never terminate.

> mkClosure :: (a -> a -> Bool) -> (a -> a) -> a -> a
> mkClosure eq f = match . iterate f
> where
> match (a:b:_) | a `eq` b = a
> match (_:c) = match c
> match [] = error "Can't happen: match []"
> mkClosure eq f = until (\x -> eq x (f x)) f

\subsection{Implementation of FIRST}

Expand All @@ -38,23 +37,25 @@ This will never terminate.
> , lookupProdsOfName = prodsOfName
> , non_terminals = nts
> })
> = joinSymSets (\ h -> maybe (Set.singleton h) id (lookup h env) )
> = joinSymSets (\h ->fromMaybe (Set.singleton h) (lookup h env))
> where
> env = mkClosure (==) (getNext fst_term prodNo prodsOfName)
> [ (name,Set.empty) | name <- nts ]
> env = mkClosure (==) (updateFirstSets fst_term prodNo prodsOfName) [(name,Set.empty) | name <- nts]

> getNext :: Name -> (a -> Production e) -> (Name -> [a])
> -> [(Name, NameSet)] -> [(Name, NameSet)]
> getNext fst_term prodNo prodsOfName env =
> [ (nm, next nm) | (nm,_) <- env ]
> updateFirstSets :: Name -> (a -> Production e) -> (Name -> [a]) -> [(Name, NameSet)]
> -> [(Name, NameSet)]
> updateFirstSets fst_term prodNo prodsOfName env = [ (nm, nextFstSet nm)
> | (nm,_) <- env ]
> where
> fn t | t == errorTok || t == catchTok || t >= fst_term = Set.singleton t
> fn x = maybe (error "attempted FIRST(e) :-(") id (lookup x env)

> next :: Name -> NameSet
> next t | t >= fst_term = Set.singleton t
> next n = Set.unions
> [ joinSymSets fn lhs
> | rl <- prodsOfName n
> , let Production _ lhs _ _ = prodNo rl ]

> terminalP :: Name -> Bool
> terminalP s = s >= fst_term

> currFstSet :: Name -> NameSet
> currFstSet s | s == errorTok || s == catchTok || terminalP s = Set.singleton s
> | otherwise = maybe (error "attempted FIRST(e) :-(")
> id (lookup s env)

> nextFstSet :: Name -> NameSet
> nextFstSet s | terminalP s = Set.singleton s
> | otherwise = Set.unions [ joinSymSets currFstSet rhs
> | rl <- prodsOfName s
> , let Production _ rhs _ _ = prodNo rl ]

0 comments on commit c31a401

Please sign in to comment.