Предварительное изучение компиляции кода (середина) — Front-End, обязательный к просмотру

переводчик

предисловие

В этой статье мы кратко попрактикуемся в лексическом анализе компилятора.Учитывая сложность реализации лексического анализа, здесь мы выбрали текстовый язык уценки в качестве объекта для краткого введения.

текст

1. Что такое уценка?

определение:

Markdown — это легкий язык разметки, основанный Джоном Грубером. Это позволяет людям писать документы в формате простого текста, который легко читать и писать, а затем преобразовывать их в действительные документы XHTML (или HTML).

Благодаря легким, удобным для чтения и написания функциям Markdown, а также поддержке изображений, диаграмм, математических выражений и блоков кода многие веб-сайты в настоящее время широко используют Markdown для написания справочных документов или публикации сообщений на форумах. .

стандартизация:

Со временем Markdown стал неофициальной спецификацией и эталонной реализацией, обычно конвертируемой в HTML, и появилось множество реализаций Markdown. Люди разработали их в основном из-за необходимости в дополнительных функциях поверх основного синтаксиса, таких как таблицы, сноски, списки определений (технически списки описаний HTML) и Markdown в блоках HTML. В то же время обращают на себя внимание некоторые неясности в неформальных нормах. Эти проблемы побудили некоторых разработчиков парсеров Markdown работать над стандартизацией.

RFC 7763 и RFC 7764 были опубликованы в марте 2016 года. RFC 7763 представил текст/уценку типа MIME из исходного варианта. RFC 7764 обсуждает и регистрирует варианты MultiMarkdown, GitHub Flavored Markdown (GFM), Pandoc, CommonMark и Markdown.

2. Связь между markdowm и html

Ниже перечислены соответствия между некоторым синтаксисом уценки и синтаксисом html.

синтаксис уценки HTML-синтаксис
# Название 1 <h1>标题</h1>
## Название 2 <h2> 标题2 </h2>
Пустые разделители строк обозначают абзацы <p></p>
Два пробела в конце строки обозначают новую строку <p> <br /> </p>
_курсив_ <em>斜体</em>
жирный <strong>粗体</strong>
`код` <code>代码<code>
--- <hr />
* 1 <ul> <li> 1 </li> </ul>

Из-за ограниченного места здесь перечислено так много грамматик.Чтобы узнать о других грамматиках, пожалуйста, обратитесь к книге "The Great Markdown".

Теперь, когда известно грамматическое соответствие между разметкой и html, как реализовать компилятор (парсер) для распознавания и преобразования грамматики?

3. лексический анализ уценки

С грамматическим стандартом уценки вы можете анализировать грамматику, то есть лексический анализ здесь, Возьмем заголовок в качестве примера.

Во-первых, лексический синтаксический анализатор необходим для создания соответствующей последовательности токенов в соответствии с грамматическими правилами заголовка.

// 词法解析器
Class Lexer {
   constructor(options) {
        this.tokens = [];
        this.tokens.links = Object.create(null);
        this.options = options || {};
        this.rules = {
           // heading 匹配规则
           heading: /^ {0,3}(#{1,6}) +([^\n]*?)(?: +#+)? *(?:\n+|$)/
           // ...
        };
    }
    // 生成 token 序列
    token(src) {
        while (src) {
            // heading
            if (cap = this.rules.heading.exec(src)) {
                src = src.substring(cap[0].length);
                this.tokens.push({
                    type: 'heading',
                    depth: cap[1].length,
                    text: cap[2]
                });
                continue;
            }
            // other

            // ...
        }
        return this.tokens;
    }
}

4. Компилировать (парсить) уценку в html

Последовательность маркеров уценки была получена выше, и ее необходимо разобрать на соответствующие теги в соответствии с грамматикой html следующим образом.

// 解析器  - Parsing & Compiling
class Parser {
    constructor(options) {
        this.tokens = [];
        this.token = null;
        this.options = options || {};
        this.renderer = new Renderer();
    }
    parse(src) {
        this.tokens = src.reverse(); // 先进先出
        var out = '';
        while (this.next()) {
            out += this.tok();
        }
        return out;
    }
    next() {
        this.token = this.tokens.pop();
        return this.token;
    }
    tok() {
        switch (this.token.type) {
         // ...
        case 'heading': {
            return this.renderer.heading(
                this.token.text,
                this.token.depth
            )
        }
        // ...
        }
    }
}
// 渲染器(代码生产器) 
class Renderer {
    constructor(options) {
        this.options = options || {};
    }
    heading(text, level, raw) {
        if (this.options.headerIds) {
            return '<h'
            + level
            + ' id="'
            + this.options.headerPrefix
            + '">'
            + text
            + '</h'
            + level
            + '>\n';
        }
        return '<h' + level + '>' + text + '</h' + level + '>\n';
    };
}

постскриптум

Поскольку markdown является языком разметки текста, нет необходимости анализировать абстрактное синтаксическое дерево (часть генерации/анализа AST) при разборе и преобразовании кода, что эквивалентно только процессу лексического анализа и генерации кода. Процесс его компиляции и разбора относительно прост по сравнению с полными по Тьюрингу языками.

Вопросы для размышления:

Можно ли построить простой синтаксический анализатор грамматики в соответствии с приоритетом сложения, вычитания, умножения и деления грамматики javascript?

Например:var a = 1 + 3 * 2;


  • Статьи по Теме

Предварительное изучение компиляции кода (ниже)