λanguage: Написання парсера

Написання парсера - це, залежно від мови програмування, досить складне завдання. У сутності, він повинен перетворити фрагмент коду (який ми аналізуємо, розглядаючи символи) у "абстрактне синтаксичне дерево" (AST). AST - це структуроване представлення програми в пам'яті, і воно "абстрактне" в тому сенсі, що не має значення, з яких саме символів складається вихідний код, але вірно відображає семантику програми. Я написав окрему сторінку, щоб описати наше AST.

Наприклад, для такого тексту програми:

sum = lambda(a, b) {
  a + b;
};
print(sum(1, 2));

наш парсер створить наступне AST, як об'єкт JavaScript:

{
  type: "prog",
  prog: [
    // first line:
    {
      type: "assign",
      operator: "=",
      left: { type: "var", value: "sum" },
      right: {
        type: "lambda",
        vars: [ "a", "b" ],
        body: {
          // the body should be a "prog", but because
          // it contains a single expression, our parser
          // reduces it to the expression itself.
          type: "binary",
          operator: "+",
          left: { type: "var", value: "a" },
          right: { type: "var", value: "b" }
        }
      }
    },
    // second line:
    {
      type: "call",
      func: { type: "var", value: "print" },
      args: [{
        type: "call",
        func: { type: "var", value: "sum" },
        args: [ { type: "num", value: 1 },
                { type: "num", value: 2 } ]
      }]
    }
  ]
}

Основна складність у написанні парсера полягає в неправильній організації коду. Парсер повинен працювати на вищому рівні, ніж просте читання символів з рядка. Кілька порад, як не писати спагетті:

  • Пишіть багато функцій і робіть їх невеликими. В кожній функції виконуйте одну річ і робіть це добре.

  • Не намагайтеся використовувати регулярні вирази для синтаксичного аналізу. Вони не працюють. Регулярні вирази можуть бути корисними у лексері, але я раджу обмежитися дуже простими речами.

  • Не намагайтеся вгадати. Якщо ви не впевнені, як парсити щось, викидайте помилку і переконайтеся, що повідомлення про помилку містить місце помилки (рядок/стовпчик).


Щоб спростити код, я розбив його на три частини, які далі розділені на багато невеликих функцій:

  1. Потік введення символів

  2. Потік введення токенів (лексер)

  3. Парсер

Поділись своїми ідеями в новій публікації.
Ми чекаємо саме на твій довгочит!
Romashka
Romashka@Romashka

Створюю інтерпретатор Mash Src

117Прочитань
1Автори
1Читачі
На Друкарні з 16 березня

Більше від автора

  • Mash Script: Рядки, string

    Стаття охоплює різні аспекти роботи з рядками в мові Mash Script, включаючи їхній літеральний запис, методи, рядки-шаблони та інше.

    Теми цього довгочиту:

    Mash Script
  • Mash Script: Оголошення функцій

    Ця публікація охоплює основи роботи з функціями в мові програмування Mash Script: оголошення, використання опціональних параметрів, повернення значень, продвинуту типізацію та створення анонімних функцій.

    Теми цього довгочиту:

    Mash Script
  • Mash Script: Базовий синтаксис

    Опис базової структури програми написаної мовою Mash Script

    Теми цього довгочиту:

    Programming

Вам також сподобається

Коментарі (1)

Хмм… Один мій знайомий сеньйор хотів реалізувати проєкт про таку штуку, яка могла б давати написати і парсер і сканер одним синтаксисом. Можливо, токени він написав отут: https://gist.github.com/kissarat/24ef777cffc18d5b0d253b56ba4e1a91

Вам також сподобається