Привет, atm Я возился с созданием компилятора, это моя попытка конвертировать случайный язык
Входные данные:
import System;
import System.Collections.Generic;
import System.Linq;
import System.Text;
import System.IO;
class Compiler
BEGIN;
private List : string Strings;
function construct()
BEGIN;
Strings = new List : string();
END;
function void start ( a : int, b : int, c : int )
BEGIN;
END;
END;
Вывод:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
class Compiler
{
private List < string Strings;
{
Strings = new List < string();
}
private void start ( int a, int b, int c,
{
}
}
Поскольку вы можете увидеть, как это работает, чтобы скомпилировать мой код с С#, за исключением списка, как я компилирую его, просто редактируя строки, которые я пробовал без учебника, просто для удовольствия и попробуйте вещи (пожалуйста, не смотрите на мой код компилятора это просто сделано со случайными вещами, которые я знал без google или что-то еще), теперь я искал google для лучших советов, но я еще ничего не нашел.
Это мой код компилятора:
public void Compile(String input, String output)
{
DirectoryCopy(input, output, true);
Console.WriteLine("Searching input directory for files.");
string[] filePaths = Directory.GetFiles(input, "*.upl",SearchOption.AllDirectories);
Console.WriteLine("Found " + filePaths.Count() + " file(s) In this directory and all sub directorys");
Console.WriteLine("Start compiling? (Y/N)");
if (Console.ReadLine().Equals("y"))
{
Console.WriteLine("Starting...");
for (int p = 0; p < filePaths.Length; p++ )
{
String[] lines = File.ReadAllLines(filePaths[p]);
for (int i = 0; i < lines.Length; i++)
{
lines[i] = lines[i].StartsWith("import ") ? lines[i].Replace("import", "using") : lines[i];
if (lines[i].Contains("function "))
{
lines[i] = lines[i].Replace("function", "private");
string[] split = lines[i].Split(' ');
for (int s = 0; s < split.Length; s++)
{
if (split[s].Contains(":"))
{
if (split[s - 1].Contains("("))
{
if (split[s + 1].Contains(","))
{
string[] split2 = split[s + 1].Split(',');
split[s - 1] = "( " + split2[0] + " " + split[s - 1][1] + ",";
split[s] = string.Empty;
split[s + 1] = split[s + 1].Split(',')[1];
}
else
{
split[s - 1] = "( " + split[s + 1] + " " + split[s - 1][1];
split[s] = string.Empty;
split[s + 1] = string.Empty;
}
}
else if (split[s + 1].Contains(")"))
{
split[s + 1] = split[s + 1].Replace(")", "");
split[s - 1] = split[s + 1] + " " + split[s - 1] + " )";
}
else
{
split[s - 1] = split[s + 1].Replace(",", "") + " " + split[s - 1] + ", ";
split[s] = string.Empty;
split[s + 1] = string.Empty;
}
}
}
split[split.Length - 1] = string.Empty;
split[split.Length - 2] = string.Empty;
lines[i] = String.Join(" ", split);
}
if (lines[i].Contains("if") || lines[i].Contains("foreach"))
{
bool insert = false;
for (int i2 = 2; i2 < lines[i].Length; i2++)
{
if (!char.IsLetter(lines[i][i2]))
{
if (insert == false)
{
char[] letters = lines[i].ToCharArray();
letters[i2] = '(';
lines[i] = String.Join("", letters);
insert = true;
}
}
}
lines[i] = !lines[i].EndsWith("BEGIN;") ? lines[i] + ")" : lines[i];
lines[i] = lines[i].Contains(":") ? lines[i].Replace(":", "in") : lines[i];
}
if (lines[i].Contains("Message"))
{
lines[i] = lines[i].Replace("Message", "MessageBox.Show(");
lines[i] = lines[i].Replace(";", " );");
}
if (lines[i].Contains("List") && lines[i].Contains(":"))
{
int spaces = 0;
char[] letters = lines[i].ToCharArray();
for (int c = 0; c < letters.Length; c++)
{
letters[c] = char.Equals(letters[c], ':') ? '<' : letters[c];
if (char.Equals(letters[c], '<'))
break;
spaces = char.IsWhiteSpace(letters[c]) ? spaces + 1 : spaces;
}
lines[i] = String.Join("", letters);
string[] spacesArr = lines[i].Split(' ');
}
lines[i] = lines[i].EndsWith("BEGIN;") || lines[i].StartsWith("BEGIN") ? lines[i].Replace("BEGIN;", "{") : lines[i];
lines[i] = lines[i].EndsWith("END;") || lines[i].Contains("END;") ? lines[i].Replace("END;", "}") : lines[i];
}
double completion = ((double)(p + 1) / (double)filePaths.Length) * 100;
Console.WriteLine("Compiled file " + (p + 1) + " of the total " + filePaths.Length + " file(s). (" + (int)completion + "%)");
int pathleng2 = output.Split('\\').Count();
string[] filepath = filePaths[p].Split('\\');
string subPath = String.Join("\\", filepath, pathleng2, (filePaths[p].Split('\\').Count() - input.Split('\\').Count()));
subPath = subPath.Replace("upl", "cs");
File.WriteAllLines(output + "\\" + subPath, lines);
}
}
}
Поэтому мой вопрос:
Кто-нибудь имеет хорошую идею, как решить эту проблему? разделите строку на слова или что-то в этом роде? возможно, токенизатор? ЕСЛИ это возможно в С#
Если у вас есть вопросы, не стесняйтесь спрашивать меня.
Вы создаете генератор кода С#, а не компилятор: он вводит ваш собственный язык в качестве ввода и создает код С# в качестве вывода.
Хорошим инструментом для такого рода вещей является парсер С# для иронии. Этот анализатор позволит вам определить и проанализировать ваш собственный язык. Это даст вам дерево разбора; который представляет собой представление вашего языка в некоторой объектной модели. Когда у вас есть это дерево разбора, вам нужно будет преобразовать его в С#.
По моему опыту определение языка и разбор его с помощью Иронии довольно легко. Преобразование дерева разбора в конечный формат - это бит.
Я использовал Ирония для разбора расширений разметки XAML в Xamlr: исходный код, который может дать вам некоторые идеи о том, как начать работу.
Для основной задачи, о которой вы говорили, любой генератор синтаксического анализа будет соответствовать - С# не хватает их. Уже упоминалась ирония, или Coco/R, GOLD, ANTLR, LLLPG, Sprache или мой NLT.
Одно замечание - код, который вы показали нам, является неправильным С#.
Если вы хотите скомпилировать, это совсем другая задача, потому что я предполагаю, что вы скомпилируете очень конкретную цель -.Net. Таким образом, ваш код должен использоваться из другого кода.Net и наоборот. Поэтому, имея в виду, что вы просто создаете другой язык.Net. Проблема заключается не в компиляции, а в правильном использовании внутри.Net.
Наверное, я бы не пошел ни с чем другим, кроме Рослина.
Не перетаскивайте всю логику одним способом. Создайте класс парсера, который реализует вспомогательные методы, которые помогут вам перемещаться по каждому символу, вроде чтения.NET, но без потока в качестве входных данных. Я не демотивирую вас из вашего проекта, но ваша попытка никуда не денется. Прежде чем продолжить, подумайте о том, чтобы написать более простые парсеры, например CSV или BB-код. Это отличная возможность. Также помните, что вы не напрямую конвертируете текст из одного формата в другой, вам нужен промежуточный класс, чтобы сначала перенести проанализированные элементы, а затем передать его генератору кода. Обратите внимание, что термин компилятор используется для компонентов, которые генерируют байтовый код, а не текст.