2017-05-29 7 views
0

Je construis un compilateur Java pour le projet universitaire, dans mon projet mes parseurs sont la plupart du temps StateT (Scope,SymbolTable) String m aScope est la portée que nous y sommes maintenant (méthode, classe, etc.) et SymbolTable détient les symboles définis jusqu'à maintenant.comment utiliser les combinateurs de mégaparsec sur StateT

Je voulais utiliser les combinateurs de mégaparsec sur les parseurs, pour parens, braces ce n'est pas problème, je viens d'utiliser mapStateT mais pour sepBy et d'autres, j'ai développé cette fonction:

mapsequence :: (Monoid s,Monad m) => (m (a,(b,s)) -> m [(a,(b,s))]) -> StateT (b,s) m a -> StateT (b,s) m [a] 
mapsequence f stm = do 
         s <- get 
         ases <- lift $ f $ runStateT stm s 
         case ases of 
         (_:_) -> do 
           put ((fst . snd . last) ases,(mconcat . map (snd . snd)) ases) 
           return $ map fst ases 
         [] -> return [] 

maintenant f serait par exemple:

\p -> p `sepBy` semi 

Quoi qu'il en soit, je réalise que ces derniers temps la fonction ci-dessus est mauvaise, la fonction exécuter l'analyseur (encapsulées dans StateT) l'alimentant l'état que nous avons en ce moment qui est s alors il fonctionnera à nouveau mais au lieu de l'alimenter le nouvel état résultant de la première exécution il l'alimentera s encore et encore et .... Comment est-ce que j'utilise les combinateurs de megaparsec comme sepBy, sepEndBy et etc. de sorte que j'exécute l'analyseur plusieurs fois mais en enchaînant l'état résultant de la première à la deuxième à la troisième etc?

+1

Cela semble faux. 'runState' devrait vous obtenir' ((b, s), a) ', pas' [a] ', de sorte que vous puissiez' mettre 'cet état. –

+0

@BartekBanachewicz l'état est '(b, s)' alors 'runState' renverrait' (a, (b, s)) ', j'exécute la fonction' f' sur le résultat pour obtenir '[((b, s), a)] ' – niceman

+1

Donc, il y a votre problème. Vous êtes à gauche avec plusieurs états. Lequel devriez-vous choisir maintenant? –

Répondre

0

Je ne sais pas pourquoi je pensais que je avais besoin d'une fonction spéciale pour ce faire, sepBy et d'autres sont définies sur Alternative et parce que chaque StateT a une fonction d'instance Alternative comme sepBy, many, etc peut être appelé directement.

Mon problème était probablement parce que je devais utiliser symbol, char, etc que je pensais sont ParsecT ... mais je me suis rendu ces fonctions sont définies en termes de MonadParsec qui StateT a classe de types instance pour donc je ne même pas encore besoin lift ou mapStateT.

Donc tout ce que j'ai fait est de changer les fonctions des signatures pour travailler avec MonadParsec et mon problème a été résolu.

0

mégaparsec dispose d'une interface de transformateur de monade ParsecT:

data ParsecT e s m a 

ParsecT e s m a est un analyseur avec le composant de données personnalisées d'erreur e, le type de flux s, monade sous-jacent m et retourner le type a.

Vous devriez pouvoir l'utiliser avec quelque chose comme type Parser = ParsecT Dec Text (State (Scope, SymbolTable)), qui ajoutera à la fonctionnalité analyse syntaxique State (Scope, SymbolTable) monade sous-jacente.

+0

tous mes parseurs sont 'StateT (Scope, SymbolTable) String (ParsecT ...) a' ici, j'ai beaucoup d'entre eux, je ne peux pas les changer facilement, de toute façon j'ai trouvé la solution et je Je vais le poster – niceman