language: F# (fsharp-2.0.0)
date: 119 days 2 hours ago
link:
visibility: public
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
open System
let testString =  List.ofArray ("not a or b and c iff (d imp e)".ToCharArray());
 
// Тип-прямая сумма с токенами
type Token =
 | LBrace | RBrace | Follows | IFF | Imp
 | And | Or | Not | True | False | Term of string
 
// Именование токенов
// TODO: сделать средствами языка
let nameToken = function
 | LBrace -> "<Token: ( >"
 | RBrace -> "<Token: ) >"
 | Follows -> "<Token: |- >"
 | IFF -> "<Token: iff >"
 | Imp -> "<Token: imp >"
 | And -> "<Token: and >"
 | Or -> "<Token: or >"
 | Not -> "<Token: not >"
 | True -> "<Token: true >"
 | False -> "<Token: false >"
 | Term(s) -> "<Token: term \"" + s + "\" >"
 
 
// Преобразование из списка символов в строку
// TODO: сделать средствами языка
let chListToString = List.fold (fun acc (chr:char) -> (acc.ToString()) + (chr.ToString())) ""
 
 
// Функция-токенайзер
let tokenize source = 
 // Накапливает символы имени, возвращает разобранное имя и остаток строки
 // На входе имя и функция-аккумулятор
 let rec getName source' acmltor = 
  match source' with
   | (')' :: _) as t -> List.rev acmltor, t                     // Завершить по скобке
   | w :: t when Char.IsWhiteSpace(w) -> List.rev acmltor, t    // Завершить по пробелу
   | [] -> List.rev acmltor, []                                 // Завершить по концу списка
   | c :: t -> getName t (c :: acmltor)                         // Иначе накапливать символы
 // Преобразует строку имени в перечисляемый тип
 let determineToken s =        
  match s with
   | "follows" -> Follows
   | "iff" -> IFF
   | "imp" -> Imp
   | "and" -> And
   | "or" -> Or
   | "not" -> Not
   | "true" -> True
   | "false" -> False
   | _ -> Term s
 // Основная функция токенайзера, выполняет лексиечский разбор
 // Требует аргумент-пустой список и возвращает токены в обратном порядке,
 // Поэтому обёрнута в функцию tokenize 
 let rec tokenize' acmltor = function
  | w :: t when Char.IsWhiteSpace(w) -> tokenize' acmltor t
  | '(' :: t -> tokenize' (LBrace :: acmltor) t
  | ')' :: t -> tokenize' (RBrace :: acmltor) t     
  | [] -> acmltor
  | term -> 
   let tokenName, tail = getName term []   
   let token = determineToken (chListToString tokenName)   
   tokenize' (token :: acmltor) tail
  | _ -> failwith "Ошибка лексического разбора"
 List.rev (tokenize' [] source)
 
// Тестируем
List.iter (fun x -> Console.WriteLine(nameToken x)) (tokenize testString)