Создание «компилятора» для редактирования строк

1

Привет, 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);
                }
            }
        }

Поэтому мой вопрос:

Кто-нибудь имеет хорошую идею, как решить эту проблему? разделите строку на слова или что-то в этом роде? возможно, токенизатор? ЕСЛИ это возможно в С#

Если у вас есть вопросы, не стесняйтесь спрашивать меня.

Теги:
string
compiler-construction

3 ответа

1
Лучший ответ

Вы создаете генератор кода С#, а не компилятор: он вводит ваш собственный язык в качестве ввода и создает код С# в качестве вывода.

Хорошим инструментом для такого рода вещей является парсер С# для иронии. Этот анализатор позволит вам определить и проанализировать ваш собственный язык. Это даст вам дерево разбора; который представляет собой представление вашего языка в некоторой объектной модели. Когда у вас есть это дерево разбора, вам нужно будет преобразовать его в С#.

По моему опыту определение языка и разбор его с помощью Иронии довольно легко. Преобразование дерева разбора в конечный формат - это бит.

Я использовал Ирония для разбора расширений разметки XAML в Xamlr: исходный код, который может дать вам некоторые идеи о том, как начать работу.

  • 0
    Привет, я знаю, что я просто разбираю свой код с высокоуровневого к высокоуровневому коду, я видел иронию, и она выглядит довольно мило, но то, что мне нужно, это хороший способ для анализа одного кода на другой или даже лучшая компиляция мой код к коду промежуточного уровня. Я видел книгу о драконах, стоит ли мне это читать?
  • 1
    Я никогда не писал компилятор, поэтому я размышляю здесь, но если вы подумаете об этом, первым шагом должно стать анализ файлов в объектной модели, которая может быть проверена и понята компилятором. Это то, что Ирония сделает для тебя. После этого вам необходимо преобразовать эту объектную модель в машинный код, который может выполнять компьютер. Может быть, посмотрите на язык бу github.com/bamboo/boo/wiki , он построен на CLR, поэтому он определяет свой собственный язык и генерирует IL. Я сомневаюсь, что вы хотели бы стать глубже, чем это!
Показать ещё 1 комментарий
1

Для основной задачи, о которой вы говорили, любой генератор синтаксического анализа будет соответствовать - С# не хватает их. Уже упоминалась ирония, или Coco/R, GOLD, ANTLR, LLLPG, Sprache или мой NLT.

Одно замечание - код, который вы показали нам, является неправильным С#.

Если вы хотите скомпилировать, это совсем другая задача, потому что я предполагаю, что вы скомпилируете очень конкретную цель -.Net. Таким образом, ваш код должен использоваться из другого кода.Net и наоборот. Поэтому, имея в виду, что вы просто создаете другой язык.Net. Проблема заключается не в компиляции, а в правильном использовании внутри.Net.

Наверное, я бы не пошел ни с чем другим, кроме Рослина.

  • 0
    Спасибо за ваш ответ. Я знаю, что делаю это неправильно, но я просто пробовал кое-что узнать, поэтому я стараюсь не использовать такие вещи, как antlr или ирония.
  • 0
    @StijnBernards, я не слежу - если вы хотите узнать, вы должны использовать эти инструменты. Вы многому научитесь. Тогда, если вы хотите узнать больше, вы можете написать свой собственный инструмент с нуля. Хорошо, у вас есть желание, энтузиазм, так что не тратьте его на переизобретение квадратного колеса, делайте это шаг за шагом.
0

Не перетаскивайте всю логику одним способом. Создайте класс парсера, который реализует вспомогательные методы, которые помогут вам перемещаться по каждому символу, вроде чтения.NET, но без потока в качестве входных данных. Я не демотивирую вас из вашего проекта, но ваша попытка никуда не денется. Прежде чем продолжить, подумайте о том, чтобы написать более простые парсеры, например CSV или BB-код. Это отличная возможность. Также помните, что вы не напрямую конвертируете текст из одного формата в другой, вам нужен промежуточный класс, чтобы сначала перенести проанализированные элементы, а затем передать его генератору кода. Обратите внимание, что термин компилятор используется для компонентов, которые генерируют байтовый код, а не текст.

  • 0
    Я знал, что перед тем, как начать, я просто сделал случайную попытку, не прибегая к помощи Google и не глядя на то, как я справлюсь с этим. Я просто пытался и делал вещи. Но мой настоящий вопрос заключается в том, как я могу сделать простой синтаксический анализатор / компилятор, что я должен использовать, как мне реализовать токенизатор или что-то в этом роде.
  • 1
    Вам нужен более систематический и организованный подход. Просто для эксперимента создайте класс, который реализует StringReader, и используйте его для переключения между сериями символов с помощью метода Read (), основываясь на каждом символе (или слове), который вы определяете при следующем действии в процессе. Если текст не соответствует ожидаемому синтаксическому анализатору, то должно быть сгенерировано исключение. Я действительно советую сначала попробовать что-то еще (и что-то более интересное), например, конвертер bbcode в HTML.
Показать ещё 3 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню