2013-12-15 2 views
20

Я учусь использовать Alex и Happy, чтобы написать небольшой компилятор. Я хочу поддерживать информацию о строках и столбцах для своих узлов АСТ, чтобы я мог предоставлять пользователю значимые сообщения об ошибках. Чтобы проиллюстрировать, как я планирую это сделать, я написал небольшой пример (см. Код ниже), и я хотел бы знать, способ, которым я столкнулся с проблемой (с подключением AlexPosn к токенам, привязка поля полиморфных атрибутов к узлам AST , используя tkPos и ​​astAttr) является хорошим стилем или если есть лучшие способы обработки информации о местоположении.Управление информацией о местоположении с помощью Alex and Happy

Lexer.x:

{ 
module Lexer where 
} 

%wrapper "posn" 

$white = [\ \t\n] 

tokens :- 

$white+ ; 
[xX] { \pos s -> MkToken pos X } 
"+" { \pos s -> MkToken pos Plus } 
"*" { \pos s -> MkToken pos Times } 
"(" { \pos s -> MkToken pos LParen } 
")" { \pos s -> MkToken pos RParen } 

{ 
data Token = MkToken AlexPosn TokenClass 
      deriving (Show, Eq) 

data TokenClass = X 
       | Plus 
       | Times 
       | LParen 
       | RParen 
        deriving (Show, Eq) 

tkPos :: Token -> (Int, Int) 
tkPos (MkToken (AlexPn _ line col) _) = (line, col) 
} 

Parser.y:

{ 
module Parser where 

import Lexer 
} 

%name simple 
%tokentype { Token } 
%token 
    '(' { MkToken _ LParen } 
    ')' { MkToken _ RParen } 
    '+' { MkToken _ Plus } 
    '*' { MkToken _ Times } 
    x { MkToken _ X } 

%% 

Expr : Term '+' Expr  { NAdd $1 $3 (astAttr $1) } 
    | Term    { $1 } 

Term : Factor '*' Term { NMul $1 $3 (astAttr $1) } 
    | Factor   { $1 } 

Factor : x    { NX (tkPos $1) } 
     | '(' Expr ')' { $2 } 


{ 
data AST a = NX a 
      | NMul (AST a) (AST a) a 
      | NAdd (AST a) (AST a) a 
      deriving (Show, Eq) 

astAttr :: AST a -> a 
astAttr (NX a)  = a 
astAttr (NMul _ _ a) = a 
astAttr (NAdd _ _ a) = a 

happyError :: [Token] -> a 
happyError _ = error "parse error" 
} 

Main.hs:

module Main where 

import Lexer 
import Parser 

main :: IO() 
main = do 
    s <- getContents 
    let toks = alexScanTokens s 
    print $ simple toks 
+1

Найдено решение, которое вы хотите поделиться? Интересно о том же – mfaerevaag

ответ

1

лично я бы очень хорошо со стилем вы описали , Тем не менее, это очень ручная работа, и я надеялся, по крайней мере, предоставить одну альтернативу, которой было бы легче управлять.

Если вы посмотрите немного дальше на documentation for alex wrappers, вы заметите, что в оболочках монады и монашесанта есть информация о позиции. Недостатком является то, что теперь у вас есть вся вещь, завернутая в монаду, и это немного усложняет парсер. Однако, обернув его в монаду, результатом анализа является Alex a, что означает, что вы получаете полный доступ к информации о строках и столбцах при создании ваших узлов ast. Теперь это просто удаляет часть плиты котла из лексера и не делает больше.

Делая это, вы также можете нести вокруг AlexState свой токен, но это может быть ненужным.

Если вам нужна помощь на самом деле фиксируя анализатор для обработки монада/monadstate обертку, я написал ответ о том, как мне удалось получить его работу здесь: How to use an Alex monadic lexer with Happy?

 Смежные вопросы

  • Нет связанных вопросов^_^