Browse Source

SVI Добавление парсинга модуля

SVI 2 years ago
parent
commit
ab649bb3ea

+ 1 - 1
.env

@@ -1 +1 @@
-SRC_MAIN="./src/main.obu"
+SRC_MAIN="./src/main.ou"

+ 8 - 36
internal/compiler/compiler.go

@@ -6,13 +6,12 @@ import (
 	мЛог "log"
 	мОс "os"
 
-	"p78git.ddns.net/svi/odeft/internal/module/src_rune"
-	мСинт "p78git.ddns.net/svi/odeft/internal/syntax"
+	мМод "p78git.ddns.net/svi/odeft/internal/module"
 )
 
 // Компилятор -- главный тип сервиса компилятора
 type Компилятор struct {
-	синтакис *мСинт.Синтаксис
+	модульГлав *мМод.Модуль
 }
 
 // НовКомпилятор -- возвращает новый тип компилятора
@@ -20,22 +19,13 @@ func НовКомпилятор() (*Компилятор, error) {
 	мЛог.Printf("НовКомпилятор()\n")
 	сам := &Компилятор{}
 
-	исхГлавИмя, ош := сам.главМодульПолуч()
+	модульГлавИмяФайла, ош := сам.главМодульПолуч()
 	if ош != nil {
-		return nil, мФорм.Errorf("НовКомпилятор(): при получении главного модуля, ош\n\t%w", ош)
+		return nil, мФорм.Errorf("НовКомпилятор(): при получении имени файла главного модуля, ош\n\t%w", ош)
 	}
-	исхГлавТекст, ош := сам.исхГлавЧитать(исхГлавИмя)
+	сам.модульГлав, ош = мМод.НовМодуль(модульГлавИмяФайла)
 	if ош != nil {
-		return nil, мФорм.Errorf("НовКомпилятор(): in read main module(%v), ош=\n\t%w", исхГлавТекст, ош)
-	}
-	_, ош = сам.руныКлассифицировать(исхГлавТекст)
-	if ош != nil {
-		return nil, мФорм.Errorf("НовКомпилятор(): при классификации рун главного модуля(%v), ош=\n\t%w", исхГлавИмя, ош)
-	}
-	исхРуны := []rune(исхГлавТекст)
-	сам.синтакис, ош = мСинт.НовСинтаксис(исхРуны)
-	if ош != nil {
-		return nil, мФорм.Errorf("НовКомпилятор(): при создании Синтаксис, ош=\n\t%w", ош)
+		return nil, мФорм.Errorf("НовКомпилятор(): при создании главного модуля, ош\n\t%w", ош)
 	}
 	return сам, nil
 }
@@ -43,28 +33,15 @@ func НовКомпилятор() (*Компилятор, error) {
 // Пуск -- запускает компилятор в работу
 func (сам *Компилятор) Пуск() error {
 	мЛог.Printf("Компилятор.Пуск()\n")
-	if ош := сам.синтакис.Пуск(); ош != nil {
-		return мФорм.Errorf("Компилятор.Пуск(): при работе Синтаксис в главном модуле, ош=\n\t%w", ош)
-	}
 	return nil
 }
 
-// Читает содержимое главного модуля
-func (sf *Компилятор) исхГлавЧитать(исхГлавИмя string) (string, error) {
-	бинДанные, ош := мОс.ReadFile(исхГлавИмя)
-	if ош != nil {
-		sf.printHelp()
-		return "", мФорм.Errorf("Компилятор.исхГлавЧитать(): при чтении главного модуля(%v), ош=\n\t%w", исхГлавИмя, ош)
-	}
-	return string(бинДанные), nil
-}
-
 // Получает главный модуль программы из окружния для компиляции
 func (sf *Компилятор) главМодульПолуч() (string, error) {
 	мЛог.Printf("Компилятор.главМодульПолуч()\n")
 	исхГлавИмя := мОс.Getenv("SRC_MAIN")
 	if исхГлавИмя == "" {
-		sf.printHelp()
+		sf.справкаПечать()
 		return "", мФорм.Errorf("Компилятор.главМодульПолуч(): env SRC_MAIN not set")
 	}
 	return исхГлавИмя, nil
@@ -83,11 +60,6 @@ const (
 )
 
 // Печатает справку по использованию
-func (sf *Компилятор) printHelp() {
+func (sf *Компилятор) справкаПечать() {
 	мЛог.Print(справкаПоЗапуску)
 }
-
-// Классифицирует руны исходника
-func (сам *Компилятор) руныКлассифицировать(текстИсх string) ([]src_rune.ИсхРуна, error) {
-	return nil, мФорм.Errorf("Компилятор.руныКлассифицировать(): доделать")
-}

+ 96 - 0
internal/module/litera/litera.go

@@ -0,0 +1,96 @@
+// package litera -- руна исходника
+package litera
+
+import (
+	мФорм "fmt"
+	мЮникод "unicode"
+
+	мАлиас "p78git.ddns.net/svi/odeft/pkg/alias"
+	мКонст "p78git.ddns.net/svi/odeft/pkg/cons"
+)
+
+// Литера -- руна исходника
+type Литера struct {
+	знач мАлиас.Литера  // Хранимая руна
+	тип  мАлиас.РунаТип // Тип руны
+}
+
+// НовЛитера -- возвращает новую литеру
+func НовЛитера(литера мАлиас.Литера) (*Литера, error) {
+	if литера == "" {
+		return nil, мФорм.Errorf("НовЛитера(): литера пустая")
+	}
+	сам := &Литера{
+		знач: литера,
+	}
+	if ош := сам.типУст(); ош != nil {
+		return nil, мФорм.Errorf("НовЛитера(): при проверке типа, ош=\n\t%w", ош)
+	}
+	return сам, nil
+}
+
+// Устанавливает тип руны
+func (сам *Литера) типУст() error {
+	руна := []rune(сам.знач)[0]
+	switch {
+	case мЮникод.IsLetter(руна):
+		сам.тип = мКонст.Буква
+	case мЮникод.IsDigit(руна):
+		сам.тип = мКонст.Цифра
+	case сам.знач == " ":
+		сам.тип = мКонст.Разделитель
+	case сам.знач == ".":
+		сам.тип = мКонст.Точка
+	case сам.знач == "\n":
+		сам.тип = мКонст.ПереводСтроки
+	case сам.знач == "-":
+		сам.тип = мКонст.Дефис
+	case сам.знач == ":":
+		сам.тип = мКонст.Двоеточие
+	case сам.знач == "#":
+		сам.тип = мКонст.КомментСтроч
+	case сам.знач == "=":
+		сам.тип = мКонст.Равно
+	case сам.знач == ";":
+		сам.тип = мКонст.ТчкЗпт
+	case сам.знач == "{":
+		сам.тип = мКонст.СкобкаФигурОткр
+	case сам.знач == "}":
+		сам.тип = мКонст.СкобкаФигурЗакр
+	case сам.знач == "'":
+		сам.тип = мКонст.КавычОдинар
+	case сам.знач == "/":
+		сам.тип = мКонст.СлэшАп
+	case сам.знач == "\\":
+		сам.тип = мКонст.СлэшДаун
+	case сам.знач == "*":
+		сам.тип = мКонст.Звезда
+	case сам.знач == "(":
+		сам.тип = мКонст.СкобкаКругОткр
+	case сам.знач == ")":
+		сам.тип = мКонст.СкобкаКругЗакр
+	case сам.знач == "[":
+		сам.тип = мКонст.СкобкаКвадрОткр
+	case сам.знач == "]":
+		сам.тип = мКонст.СкобкаКвадрЗакр
+	case сам.знач == ",":
+		сам.тип = мКонст.Запятая
+	case сам.знач == "!":
+		сам.тип = мКонст.ЗнакВоскл
+	case сам.знач == "?":
+		сам.тип = мКонст.ЗнакВопр
+	default:
+		return мФорм.Errorf("Литера.типУст(): неизвестный тип руны('%v')", string(сам.знач))
+	}
+	return nil
+}
+
+// Знач -- возвращает хранимое значение руны
+func (сам *Литера) Знач() мАлиас.Литера {
+	return мАлиас.Литера(сам.знач)
+}
+
+// Тип -- возвращае ттип руны
+func (сам *Литера) Тип() мАлиас.РунаТип {
+	return сам.тип
+}

+ 96 - 5
internal/module/module.go

@@ -3,22 +3,113 @@ package module
 
 import (
 	мФорм "fmt"
-	мИсхРуна "p78git.ddns.net/svi/odeft/internal/module/src_rune"
+	мЛог "log"
+	мОс "os"
+	мСтр "strings"
+
+	мЛит "p78git.ddns.net/svi/odeft/internal/module/litera"
+	мАлиас "p78git.ddns.net/svi/odeft/pkg/alias"
+	мКонст "p78git.ddns.net/svi/odeft/pkg/cons"
 )
 
 // Модуль -- тип модуля для компилятора
 type Модуль struct {
-	имя     string
-	списРун []мИсхРуна.ИсхРуна
+	имя            string
+	имяФайла       string
+	списЛит        []*мЛит.Литера
+	списЛитКоммент []*мЛит.Литера
 }
 
 // НовМодуль -- возвращает новый модуль
-func НовМодуль(имя string) (*Модуль, error) {
+func НовМодуль(имяФайла string) (*Модуль, error) {
+	if имяФайла == "" {
+		return nil, мФорм.Errorf("НовМодуль(): имя файла модуля пустое")
+	}
+	списИмяФайла := мСтр.Split(имяФайла, "/")
+	имя := списИмяФайла[len(списИмяФайла)-1]
 	if имя == "" {
 		return nil, мФорм.Errorf("НовМодуль(): имя модуля пустое")
 	}
+	if !мСтр.HasSuffix(имяФайла, ".ou") {
+		return nil, мФорм.Errorf("НовМодуль(): имя файла модуля(%v) имеет неправильное окончание", имяФайла)
+	}
+	имя = мСтр.TrimSuffix(имя, ".ou")
 	сам := &Модуль{
-		имя: имя,
+		имяФайла:       имяФайла,
+		имя:            имя,
+		списЛит:        []*мЛит.Литера{},
+		списЛитКоммент: []*мЛит.Литера{},
+	}
+	if ош := сам.файлПрочитать(); ош != nil {
+		return nil, мФорм.Errorf("НовМодуль(): при чтении файла, ош=\n\t%w", ош)
+	}
+	if ош := сам.найтиНачало(); ош != nil {
+		return nil, мФорм.Errorf("НовМодуль(): при поиске начала модуля ('%v'), ош=\n\t%w", сам.имя, ош)
 	}
 	return сам, nil
 }
+
+// Ищет в литерах начало модуля
+func (сам *Модуль) найтиНачало() error {
+	{ // Поиск начала имени модуля
+		адр := -1
+		словоКонтр := []rune("модуль ")
+		еслиНайдено := false
+		for {
+			if len(сам.списЛит) == 0 {
+				break
+			}
+			адр++
+			литера := сам.списЛит[0]
+			сам.списЛит = сам.списЛит[1:]
+			if литера.Тип() != мКонст.Буква {
+				сам.списЛитКоммент = append(сам.списЛитКоммент, литера)
+				сам.списЛит = сам.списЛит[1:]
+				continue
+			}
+			if литера.Знач() == мАлиас.Литера(словоКонтр[0]) {
+				словоКонтр = словоКонтр[1:]
+				if len(словоКонтр) == 0 {
+					мЛог.Printf("Модуль.найтиНачало(): начало модуля найдено")
+					еслиНайдено = true
+					break
+				}
+				continue
+			}
+			словоКонтр = []rune("модуль ")
+		}
+		if !еслиНайдено {
+			return мФорм.Errorf("Модуль.найтиНачало(): не найдено начало модуля")
+		}
+	}
+	{ // Теперь определить наличие разделителя
+		имяПоиск := мАлиас.Литера("")
+		for {
+			литера := сам.списЛит[0]
+			if литера.Тип() != мКонст.Буква {
+				return мФорм.Errorf("Модуль.найтиНачало(): за ключевым словом 'модуль' нет имени модуля")
+			}
+			имяПоиск += литера.Знач()
+			сам.списЛит = сам.списЛит[1:]
+		}
+
+	}
+}
+
+// Читает текст исходного файла
+func (сам *Модуль) файлПрочитать() error {
+	бинДанные, ош := мОс.ReadFile(сам.имяФайла)
+	if ош != nil {
+		return мФорм.Errorf("Модуль.файлПрочитать(): при чтении файла(`%v`), ош=\n\t%w", сам.имяФайла, ош)
+	}
+	стрДанные := string(бинДанные)
+	for _, _руна := range стрДанные {
+		руна, ош := мЛит.НовЛитера(мАлиас.Литера(_руна))
+		if ош != nil {
+			return мФорм.Errorf("Модуль.файлПрочитать(): при создании руны(`%v`), ош=\n\t%w", string(_руна), ош)
+		}
+		сам.списЛит = append(сам.списЛит, руна)
+	}
+	мЛог.Printf("Модуль.файлПрочитать(): всего рун в модуле '%v' = %v\n", сам.имя, len(сам.списЛит))
+	return nil
+}

+ 0 - 47
internal/module/src_rune/src_rune.go

@@ -1,47 +0,0 @@
-// package src_rune -- руна исходника
-package src_rune
-
-import (
-	мФорм "fmt"
-	мЮникод "unicode"
-)
-
-const ( // Класс литеры
-	буква     = "буква"
-	цифра     = "цифра"
-	пробел    = "пробел"
-	точка     = "точка"
-	новСтрока = "\n"
-)
-
-// ИсхРуна -- руна исходника
-type ИсхРуна struct {
-	знач rune   // Хранимая руна
-	тип  string // Тип руны
-}
-
-// НовИсхРуна -- возвращае тновую руну исходника
-func НовИсхРуна(руна rune) (*ИсхРуна, error) {
-	сам := &ИсхРуна{
-		знач: руна,
-	}
-	if ош := сам.типУст(); ош != nil {
-		return nil, мФорм.Errorf("НовИсхРуна(): при проверке типа, ош=\n\t%w", ош)
-	}
-	return сам, nil
-}
-
-// Устанавливает тип руны
-func (сам *ИсхРуна) типУст() error {
-	if мЮникод.IsLetter(сам.знач) {
-		сам.тип = буква
-	}
-	if мЮникод.IsDigit(сам.знач) {
-		сам.тип = цифра
-	}
-	if сам.тип == "" {
-		сам.тип = "неизвестно"
-		return мФорм.Errorf("ИсхРуна.типУст(): неизвестный тип руны (%v)", сам.знач)
-	}
-	return nil
-}

+ 8 - 0
pkg/alias/alias.go

@@ -0,0 +1,8 @@
+// package alias -- алиасы типов
+package alias
+
+// Литера -- специальный тип литеры
+type Литера string
+
+// РунаТип -- тип руны
+type РунаТип string

+ 38 - 0
pkg/cons/cons.go

@@ -0,0 +1,38 @@
+// package cons -- константы компилятора
+package cons
+
+import (
+	мАлиас "p78git.ddns.net/svi/odeft/pkg/alias"
+)
+
+const ( // Класс литеры
+	Буква           = мАлиас.РунаТип("буква")
+	Цифра           = мАлиас.РунаТип("цифра")
+	Пробел          = мАлиас.РунаТип("пробел")
+	Точка           = мАлиас.РунаТип("точка")
+	Разделитель     = мАлиас.РунаТип("разделитель") // Например, пробел, таблуция
+	ПереводСтроки   = мАлиас.РунаТип("перевод_строки")
+	Дефис           = мАлиас.РунаТип("дефис")
+	Двоеточие       = мАлиас.РунаТип("двоеточие")
+	ТчкЗпт          = мАлиас.РунаТип("точка_с_запятой")
+	КавычОдинар     = мАлиас.РунаТип("кавычка_одиночная")
+	КомментСтроч    = мАлиас.РунаТип("строчный_комментарий")
+	НовСтрока       = мАлиас.РунаТип("новая_строка")
+	Равно           = мАлиас.РунаТип("равно")
+	СлэшАп          = мАлиас.РунаТип("/")
+	СлэшДаун        = мАлиас.РунаТип("\\")
+	Звезда          = мАлиас.РунаТип("*")
+	СкобкаФигурОткр = мАлиас.РунаТип("скобка_фигурная_откр")
+	СкобкаФигурЗакр = мАлиас.РунаТип("скобка_фигурная_закр")
+
+	СкобкаКругОткр = мАлиас.РунаТип("скобка_круглая_откр")
+	СкобкаКругЗакр = мАлиас.РунаТип("скобка_круглая_закр")
+
+	СкобкаКвадрОткр = мАлиас.РунаТип("скобка_квадратная_откр")
+	СкобкаКвадрЗакр = мАлиас.РунаТип("скобка_квадратная_закр")
+
+	Запятая = мАлиас.РунаТип("запятая")
+
+	ЗнакВоскл = мАлиас.РунаТип("знак_воскл")
+	ЗнакВопр  = мАлиас.РунаТип("знак_вопр")
+)

+ 10 - 8
src/main.ou

@@ -8,8 +8,8 @@
 модуль Главный;
 
 импорт {
-    СИСТЕМА  =``;
-    Лог = `#/log.obu`;
+    СИСТЕМА  ='';
+    Лог = '#/log.obu';
 }
 
 конст {
@@ -58,19 +58,21 @@
 }
 
 {
-    Лог.СтрокаПеревод(`Привет, мир!`);
+    Лог.СтрокаПеревод('Привет, мир!');
     журнал = ?Журнал{
         год:2005;
     }
     журнал.год = 2020;
-    ош = журнал.Открыть("Пионер");
-    если ош.есть {
-        Лог.Строка(`При открытии журнала, ош=\n\t`);
-        Лог.СтрокаПеревод(ош.знач);
+    ош = журнал.Открыть('Пионер');
+    если !ош.есть{
+        Лог.СтрокаПеревод('Ошибок нет!');
+        вернуть
     }
+    Лог.Строка('При открытии журнала, ош=\n\t');
+    Лог.СтрокаПеревод(ош.знач);
     ош = журнал.Закрыть();
     если ош.есть {
-        Лог.Строка(`При закрытии журнала, ош=\n\t`);
+        Лог.Строка('При закрытии журнала, ош=\n\t');
         Лог.СтрокаПеревод(ош.знач);
     }
 }.