Skip to content

Latest commit

 

History

History
166 lines (122 loc) · 7.52 KB

File metadata and controls

166 lines (122 loc) · 7.52 KB

Руководство по Alex

Внимание. Этот документ в процессе написания.

Это перевод руководства по Alex версии 3.0. Перевод осуществил Симоненко Евгений [email protected].

Введение

Alex это инструмент для генерирования лексических анализаторов на Haskell на основе описание токенов, которые должны быть распознаны в виде регулярных выражений. Alex похож на такие инструменты как lex и flex для C/C++.

Alex принимает описание токенов на основе регулярных выражений и генерирует модуль на Haskell, содержащий код для эффективного сканирования текста. Alex разработан так, чтобы быть знакомым для пользователей lex, хотя в действительности он отличается от lex в нескольких отношениях.

Пример спецификации приведён на рисунке 2.1. Первые несколько строк между { и } предоставляют кусок кода на Haskell, который будет вставлен в вывод непосредственно, этот кусок вверху модуля -- обычная практика по объявлению имени модуля для генерируемого кода на Haskell, в данном случае это Main.

Следующая строка, % wrapper "basic", определяет, какой код поддержки должен производить Alex вместе с основным сканером. Обёртка basic выбирает сканер, который токенизирует строку и возвращает список токенов. Обёртки подробно описаны в Глава "Интерфейс к созданному Alex лексеру".

Следующие две строки определяют макросы $digit и $alpha для использования в определениях токенов.

Строка tokens :- заканчивает определение макросов и начинает определение сканера.

Сканер специфицируется в виде серии определений токенов, где каждая спецификация токена принимает форму

regexp { code }

Назначение этого правила: «если вход соответствует regexp, вернуть code». Часть кода вместе с фигурными скобками может быть заменена на просто ;, что означает, что во входном потоке этот токен следует игнорировать. Как вы можете видеть, мы использовали это, чтобы игнорировать в нашем примере пробел.

Наш сканер настроен так, что действия являются функциями типа String -> Token. Когда токен сопоставлен, часть входного потока, который он сопоставил, передается соответствующей функции действия в виде строки.

В нижней части файла есть еще один фрагмент кода, окруженный фигурными скобками { ... }. В этом фрагменте мы объявляем тип токенов и предоставляем функцию main, которую мы можем использовать для тестирования; функция main просто выполняет токенизацию ввода и печатает результаты на стандартный вывод.

Alex любезно предоставил следующую функцию, которую мы можем использовать для вызова сканера:

alexScanTokens :: String -> [Token]

Alex организует токенизацию входного потока, каждой из функций действия передается соответствующая строка, а как результат возвращается список токенов. Если входной поток ленив, выходной поток также будет производиться лениво.

Здесь мы продемонстрировали простейшую форму сканера, которая была выбрана строкой %wrapper "basic" в верхней части файла. В общем случае, действия не обязаны иметь тип String -> Token, и сканер не обязан возвращать список токенов.

Для этой спецификации в файле Tokens.x Alex можно использовать для создания Tokens.hs:

{
module Main (main) where
}

%wrapper "basic"

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

tokens :-

  $white+ ;
  "--".* ;
  let { \s -> Let }
  in { \s -> In }
  $digit+ { \s -> Int (read s) }
  [\=\+\-\*\/\(\)] { \s -> Sym (head s) }
  $alpha [$alpha $digit \_ \’]* { \s -> Var s }

{
-- Each action has type :: String -> Token

-- The token type:
data Token =
  Let |
  In |
  Sym Char |
  Var String |
  Int Int
  deriving (Eq,Show)

main = do
  s <- getContents
  print (alexScanTokens s)
}

(Рис. 2.1.)

alex Tokens.x

Если модуль необходимо поместить в другой файл, например Main.hs, то имя выходного файла можно указать, используя опцию -o:

alex Tokens.x -o Main.hs

Получаемый модуль совместим с Haskell 98. Его также можно легко использовать с парсером Happy (https://www.haskell.org/happy/).

Файлы Alex

В этом разделе мы описываем формат лексической спецификации Alex.

Лексический синтаксис

Лексический синтаксис Alex приведен ниже. Он написан как набор макроопределений с использованием собственного синтаксиса Alex. Эти макросы используются позже в BNF спецификации синтаксиса.

$digit = [0-9]
$octdig = [0-7]
$hexdig = [0-9A-Fa-f]
$special = [\.\;\,\$\|\*\+\?\#\~\-\{\}\(\)\[\]\^\/]
$graphic = $printable # $white

@string = \" ($graphic # \")* \"
@id = [A-Za-z][A-Za-z’_]*
@smac = ’$’ id
@rmac = ’@’ id
@char = ($graphic # $special) | @escape
@escape = ’\\’ ($printable | ’x’ $hexdig+ | ’o’ $octdig+ | $digit+)
@code = -- curly braces surrounding a Haskell code fragment

Синтаксис фалов Alex

...

Ссылки


(c) 2018, Симоненко Евгений