Files
srab/исх/форматы/джесон/лексер.tri
2025-11-26 21:32:41 +03:00

297 lines
13 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
модуль джесон
импорт "стд::строки"
импорт "исх/массивы"
импорт "исх/спринтф"
// да, это тоже цифры. просто поверьте
пусть цифры = массивы.Строки["1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "-", "+"]
тип ДжесонТокен = класс {
}
фн (токен: ДжесонТокен) в строку(): Строка {
вернуть "пустой токен. где вы его взяли вообще?"
}
тип ДжесонТокены = []ДжесонТокен
фн массив токенов в строку(токены: ДжесонТокены): Строка {
пусть рез := ""
цикл [номер]токен среди токены {
рез := строки.собрать(рез, токен.в строку())
}
вернуть рез
}
тип ТокенФигурнаяСкобка = класс(ДжесонТокен) {
закрывающая: Лог := ложь
}
фн (токен: ТокенФигурнаяСкобка) в строку(): Строка {
если токен.закрывающая {
вернуть "}"
} иначе {
вернуть "{"
}
}
тип ТокенКвадратнаяСкобка = класс(ДжесонТокен) {
закрывающая: Лог := ложь
}
фн (токен: ТокенКвадратнаяСкобка) в строку(): Строка {
если токен.закрывающая {
вернуть "]"
} иначе {
вернуть "["
}
}
тип ТокенЗапятая = класс(ДжесонТокен) {
}
фн (токен: ТокенЗапятая) в строку(): Строка {
вернуть ","
}
тип ТокенДвоеточие = класс(ДжесонТокен) {
}
фн (токен: ТокенДвоеточие) в строку(): Строка {
вернуть ":"
}
тип ТокенЧисло = класс(ДжесонТокен) {
значение: Цел64 := 0
}
фн (токен: ТокенЧисло) в строку(): Строка {
вернуть спринтф.ф("$цел", токен.значение)
}
тип ТокенСтрока = класс(ДжесонТокен) {
значение: Строка := ""
}
фн (токен: ТокенСтрока) в строку(): Строка {
пусть строка := строки.заменить все(токен.значение, "\\", "\\\\")
строка := строки.заменить все(строка, "\"", "\\\"")
вернуть спринтф.ф("\"$стр\"", строка)
}
тип ТокенБульБуль = класс(ДжесонТокен) {
значение: Лог := ложь
}
фн (токен: ТокенБульБуль) в строку(): Строка {
если токен.значение {
вернуть "true"
} иначе {
вернуть "false"
}
}
фн съесть символ(стр := Строка, ошибка := Строка): Строка {
пусть символ = посмотреть но не трогать(стр, ошибка)
если ошибка # "" { вернуть "" }
стр := строки.извлечь(стр, 1, длина(стр(:Строка8)) - 1)
вернуть символ
}
фн съесть конкретный символ(стр := Строка, ожидаемый символ: Строка, ошибка := Строка): Строка {
пусть символ = посмотреть конкретный символ но не трогать(стр, ожидаемый символ, ошибка)
если ошибка # "" { вернуть "" }
стр := строки.извлечь(стр, 1, длина(стр(:Строка8)) - 1)
вернуть символ
}
фн посмотреть но не трогать(стр := Строка, ошибка := Строка): Строка {
если длина(стр) = 0 {
ошибка := "нежданный конец строки"
вернуть ""
}
пусть символ := строки.извлечь(стр, 0, 1)
вернуть символ
}
фн посмотреть конкретный символ но не трогать (стр := Строка, ожидаемый символ: Строка, ошибка := Строка): Строка {
если длина(стр) = 0 {
ошибка := спринтф.ф("нежданный конец строки, ожидался символ '$символ'", ожидаемый символ)
вернуть ""
}
пусть символ = строки.извлечь(стр, 0, 1)
если символ # ожидаемый символ {
ошибка := спринтф.ф("ожидался символ '$стр', а пришёл '$символ'", ожидаемый символ, символ)
вернуть ""
}
вернуть символ
}
фн читать число(стр := Строка, ошибка := Строка): Цел64 {
пусть число := ""
пока истина {
пусть символ = посмотреть но не трогать(стр, ошибка)
если ошибка # "" { вернуть 0 }
пусть является цифрой := ложь
пусть является знаком := ложь
цикл [номер]цифра среди цифры {
если символ = цифра {
является цифрой := истина
прервать
}
}
если является цифрой {
число := строки.собрать(число, символ)
стр := строки.извлечь(стр, 1, длина(стр(:Строка8)) - 1)
} иначе {
если длина(число) = 0 {
ошибка := спринтф.ф("ожидалось число, а пришёл '$символ'", символ)
вернуть 0
}
пусть целое := 0
пусть номер байта зачем он тебе нужен вообще глупая машина := 0
пусть мне повезло = строки.извлечь цел(число, номер байта зачем он тебе нужен вообще глупая машина, целое)
если ~мне повезло {
ошибка := спринтф.ф("ошибка преобразования числа '$число'", число)
}
вернуть целое
}
}
вернуть 0
}
фн читать строку(стр := Строка, ошибка := Строка): Строка {
съесть конкретный символ(стр, "\"", ошибка)
если ошибка # "" { вернуть "" }
пусть экран := ложь
пусть строка := ""
пока истина {
пусть символ = съесть символ(стр, ошибка)
если ошибка # "" { вернуть "" }
если символ = "\\" {
экран := ~экран
} иначе если символ = "\"" & ~экран {
вернуть строка
} иначе {
экран := ложь
строка := строки.собрать(строка, символ)
}
}
вернуть строка
}
фн читать буль буль(стр := Строка, ошибка := Строка): Лог {
пусть истинаСтр = "true"
пусть ложьСтр = "false"
если строки.есть префикс(стр, истинаСтр) {
стр := строки.извлечь(стр, длина(истинаСтр(:Строка8)), длина(стр(:Строка8)) - длина(истинаСтр(:Строка8)))
вернуть истина
} иначе если строки.есть префикс(стр, ложьСтр) {
стр := строки.извлечь(стр, длина(ложьСтр(:Строка8)), длина(стр(:Строка8)) - длина(ложьСтр(:Строка8)))
вернуть ложь
} иначе {
пусть символ = посмотреть но не трогать(стр, ошибка)
если ошибка # "" { вернуть ложь }
ошибка := спринтф.ф("ожидалось 'true' или 'false', а пришёл '$символ'", символ)
вернуть ложь
}
}
фн токенизировать(стр: Строка, ошибка := Строка): ДжесонТокены {
пусть токены = ДжесонТокены[]
пусть сколько открыто := 0
пока истина {
если длина(стр) = 0 & сколько открыто = 0 {
прервать
}
пусть символ = посмотреть но не трогать(стр, ошибка)
если ошибка # "" { вернуть ДжесонТокены[] }
пусть является цифрой := ложь
цикл [номер]цифра среди цифры {
если символ = цифра {
является цифрой := истина
прервать
}
}
если символ = " " | символ = "\n" | символ = "\r" | символ = "\t" {
стр := строки.извлечь(стр, 1, длина(стр(:Строка8)) - 1)
} иначе если символ = "{" {
стр := строки.извлечь(стр, 1, длина(стр(:Строка8)) - 1)
токены.добавить(ТокенФигурнаяСкобка{закрывающая: ложь})
сколько открыто := сколько открыто + 1
} иначе если символ = "}" {
стр := строки.извлечь(стр, 1, длина(стр(:Строка8)) - 1)
токены.добавить(ТокенФигурнаяСкобка{закрывающая: истина})
сколько открыто := сколько открыто - 1
} иначе если символ = "[" {
стр := строки.извлечь(стр, 1, длина(стр(:Строка8)) - 1)
токены.добавить(ТокенКвадратнаяСкобка{закрывающая: ложь})
} иначе если символ = "]" {
стр := строки.извлечь(стр, 1, длина(стр(:Строка8)) - 1)
токены.добавить(ТокенКвадратнаяСкобка{закрывающая: истина})
} иначе если символ = "," {
стр := строки.извлечь(стр, 1, длина(стр(:Строка8)) - 1)
токены.добавить(ТокенЗапятая{})
} иначе если символ = ":" {
стр := строки.извлечь(стр, 1, длина(стр(:Строка8)) - 1)
токены.добавить(ТокенДвоеточие{})
} иначе если является цифрой {
пусть число = читать число(стр, ошибка)
если ошибка # "" { вернуть ДжесонТокены[] }
токены.добавить(ТокенЧисло{значение: число})
} иначе если символ = "\"" {
пусть строка = читать строку(стр, ошибка)
если ошибка # "" { вернуть ДжесонТокены[] }
токены.добавить(ТокенСтрока{значение: строка})
} иначе если символ = "t" | символ = "f" {
пусть буль = читать буль буль(стр, ошибка)
если ошибка # "" { вернуть ДжесонТокены[] }
токены.добавить(ТокенБульБуль{значение: буль})
} иначе {
ошибка := спринтф.ф("внезапный символ '$стр'", символ)
вернуть ДжесонТокены[]
}
}
вернуть токены
}