Получение информации о номере строки на этапе семантического анализа (с использованием Alex,Happy)

Я делаю семантический анализ для экспериментального языка. Я использую Alex и Happy для генерации лексера и анализатора (на самом деле я использую инструмент BNFC для генерации файлов Alex и Happy). Я хотел получить сообщение об ошибке с номером строки и номером столбца всякий раз, когда есть семантическая ошибка, скажем, ошибка типа.

Кажется, мне нужно было бы хранить информацию о номере строки при построении моей таблицы символов или AST. Моя проблема была бы решена, если бы я мог каким-то образом получить доступ к информации о положении в разделах правил файла Happy.

Любые предложения в этом отношении будут высоко оценены.

Я попытался реализовать предложенный ниже ответ, но, к сожалению, не добился успеха. Давайте рассмотрим очень простую грамматику:

Expr -> Expr + Term
       | Term
Term -> Int

Мой лексер для этого выглядит ниже.

%wrapper "posn"

$digit = 0-9            -- digits
$alpha = [a-zA-Z]       -- alphabetic characters

tokens :-

  $white+               ;
  "--".*                ;
  $digit+               { \p s -> L {getPos = p , unPos = Tok_Int (read s) }}
  \+                    { \p s -> L {getPos = p , unPos = Tok_Plus} }


{
data L a = L{ getPos :: AlexPosn, unPos :: a } deriving (Eq,Show)

data Token =
      Tok_Plus 
    | Tok_Int Int 
    deriving (Eq,Show)


getToken :: IO [L Token]
getToken = do 
    args <- getArgs
    case length args == 0 of
        True  -> do 
               error $ "\n****************Error: Expecting file name as an argument.\n" 
        False -> do
            let fname  = args !! 0 
            conts <- readFile fname
            let tokens = alexScanTokens conts 
            return tokens 

}

Мой файл Yacc как под, и это то, где я борюсь. Как встроить информацию о положении в мое синтаксическое дерево.

{
{-# OPTIONS_GHC -fno-warn-incomplete-patterns -fno-warn-overlapping-patterns #-}
module Parser where
import Lexer

}

%name pExpr Exp 
%name pTerm Term 

%tokentype {L Token}
%error { parseError }

%token
      int             { L { getPos = _,unPos = Tok_Int $$ } }
      '+'             { L { getPos = _,unPos = Tok_Plus } }

%%
Exp :: {L Expr} 
Exp  : Exp '+' Term           { L { getPos =  getPos $1 , unPos = EAdd (unPos $1) (unPos $3) } }
     | Term                   { $1 }

Term :: {L Expr}
Term : int                   { L {getPos =  getPos $1, unPos =  EInt (unPos $1) } } 

{

data Expr =  EAdd Expr Expr 
            | EInt Int 
            deriving (Eq,Show)


returnM :: a -> Err a
returnM = return

thenM :: Err a -> (a -> Err b) -> Err b
thenM = (>>=)


parseError :: [L Token] -> a
parseError _ = error "Parse error"

}

Я получаю следующие ошибки типа при попытке скомпилировать сгенерированный файл Haskell.

Parser.hs:109:39:
    Couldn't match expected type `L a0' with actual type `Int'
    In the first argument of `getPos', namely `happy_var_1'
    In the `getPos' field of a record
    In the first argument of `HappyAbsSyn5', namely
      `(L {getPos = getPos happy_var_1,
           unPos = EInt (unPos happy_var_1)})'

Parser.hs:109:73:
    Couldn't match expected type `L Int' with actual type `Int'
    In the first argument of `unPos', namely `happy_var_1'
    In the first argument of `EInt', namely `(unPos happy_var_1)'
    In the `unPos' field of a record

Ребята, можете ли вы предложить мне, как заставить эту вещь работать?

1 ответ

Вы можете иметь доступ к информации о положении в счастливом правиле, если они доступны в вашем выводе лексера. Это именно то, как, например, сам GHC ставит SrcLocв его собственное внутреннее представление кода на Haskell.

По сути, вы бы использовали posn Алекс-оболочка для ввода информации о позиции в ваш тип токена:

data L a = L{ getPos :: AlexPosn, unPos :: a }

(так что ваш токенайзер Алекс вернется L Token ценности); а затем вы объединяете отдельные позиции токена в своем счастливом правиле в позицию для нетерминала (например, вы можете получить правило из Expr + Expr в L (combinedPosn [getPos $1, getPos $2, getPos $3] $ PlusExpr (unPos $1) (unPos $3),

Другие вопросы по тегам