Определение, фонетический (звуко-буквенный) разбор и разбор слова по составу
На данной странице представлено лексическое значение слова «проводить», а также сделан звуко-буквенный разбор и разбор слова по составу с транскрипцией и ударениями.Оглавление:
- Значение слова
- Звуко-буквенный разбор
- Разбор по составу
Значение слова
1.
ПРОВОДИТЬ1, ожу, одишь; несов.
1. см. провести.
2. (1 и 2 л. не употр.), что. Быть проводником2 (в 1 знач.) чего-н. Металл хорошо проводит электричество.
2.
ПРОВОДИТЬ2, ожу, одишь; сов.
1. кого (что). Прощаясь, провести, пойти вместе с кем-н. до какого-н. места. П. друга на вокзал.
2. кого-что.
3. кого-что. Проследить за уходящим, уезжающим. П. глазами пешехода.
4. кого-что. Расставаясь, проститься. П. певца аплодисментами. П. в последний путь (проститься с умершим).
5. кого (что). То же, что выпроводить (прост.). Не хотел уходить: еле проводили.
| несов. провожать, аю, аешь. На платформе стоят провожающие (сущ.; те, кто провожает отъезжающих).
| сущ. проводы, ов (к 1, 2 и 4 знач.). Горькие п. (о похоронах). Дальние п. лишние слёзы (посл.).
Фонетический (звуко-буквенный) разбор
проводи́ть
проводить — слово из 3 слогов: про-во-дить. Ударение падает на 3-й слог.
Транскрипция слова: [правад’ит’]
п — [п] — согласный, глухой парный, твёрдый (парный)
о — [а] — гласный, безударный
в — [в] — согласный, звонкий парный, твёрдый (парный)
о — [а] — гласный, безударный
д — [д’] — согласный, звонкий парный, мягкий (парный)
и — [и] — гласный, ударный
т — [т’] — согласный, глухой парный, мягкий (парный)
ь — не обозначает звука
В слове 9 букв и 8 звуков.
Цветовая схема: проводить
Разбор слова «проводить» по составу
проводить (программа института)
проводить (школьная программа)
Части слова «проводить»: про/вод/и/ть
Часть речи: глагол
Состав слова:
про — приставка,
вод — корень,
и, ть — суффиксы,
нет окончания,
проводи — основа слова.
Примечание: ть является формообразующим суффиксом и не входит в основу слова, но во многих школьных программах ть отмечается как окончание.
Конспект урока по теме » Морфемный разбор слова» 5 класс | План-конспект урока по русскому языку (5 класс) на тему:
Урок « Морфемный разбор слова»
Цель урока: Закрепить понятие о порядке морфемного разбора;развивать навыки устного и письменного морфемного разбора ; научить проводить морфемный разбор слова; формировать навыки самоконтроля, рефлексии.
Тип урока : Комбинированный урок
Формы обучения: индивидуальная, групповая.
Задачи: научиться выделять в слове разные морфемы, определять часть речи, придумывать слова по схемам, собирать слова из разных морфем, отработать устный разбор слов, воспитывать любовь к русскому языку.
Планируемые результаты: учащиеся научатся понимать связь между морфемикой и орфографией; проводить морфемный анализ слова, морфемный разбор; применять полученные знания и умения на практике.
I. Организационый момент.
Приветствие. Проверка готовности к уроку. Выявление отсутствующих.
II. Актуализация знаний.
— Что такое морфема?
-Назовите морфемы, из которых может состоять основа слова.
— С помощью каких морфем образуются новые слова? Приведите примеры.
— Чем отличаются формы одного и того же слова от однокоренных слов? Приведите примеры.
III. Работа по теме урока.
1. Разберите по составу слова устно: трактористы, привозим, вносишь, сварщик, синеватая (даль), парашютистка, и письменно : (в) сарафанчике,уходит, щерстяным (шарфом) , тихая, безлунная (ночь). К какой части речи относятся данные слова.
Образец рассуждения:
Сварщик — сварщика. В слове нулевое окончание. Основа – сварщик – указывает , что имя существительное стоит в Им.п. ед.ч. Суффикс –чик-, он обозначает лиц по роду занятий. В слове есть приставка с-. Она имеет значение сближения, соединения, скрепления чего-либо.
Сварщик –варить , сварка, сваривать. Корень –вар -.
Комментарий
Детям необходимо напомнить, что корень в слове определяем в последнюю очередь. После выделения основы определяем суффикс и приставку, подбираем однокоренные слова с другими суффиксами и приставками, чтобы яснее выделить корень.
2. Тестовое задание
В каком слове не корня с чередующимися согласными ?
1)газета 2) снеговик 3) бегу 4) редкость
3.Придумать и записать по два слова к каждой схеме. Выполнить морфемный разбор. Схемы записаны на доске.
IV . Закрепление изученного материала.
Выпишите из любого литературного произведения ( учебник литературы) существительное, прилагательное, глагол и произведите их морфемный разбор.( Самостоятельное выполнение с последующей проверкой).
V. Занимательная лингвистика.
а) от глагола ОБГОВОРИТЬ –приставку, от ДУМАТЬ – корень, от глагола ЧИТАТЬ – суффикс , от глагола ПЕТЬ –окончание.
(ОБДУМАТЬ)
б) от прилагательного ПРЕДУТРЕННИЙ –приставку, от глагола ПОГОВОРИТЬ – тоже приставку, от слова СЛАГАЕМОЕ –корень, от глагола РЕШАТЬ – глагольный суффикс, от глагола ПИСАЛ- суффикс прошедшего времени, от СОБИРАЛА –окончание.
( предполагала)
2. Кроссворд
Ключевое слово: Раздел науки о языке, в котором изучаются наименьшие значимые части слова.
- Окончание – значимая часть слова, которая образует … слова.
- Окончание, не выраженное звуками.
- Часть речи, которая не имеет окончания.
- Суффикс, стоящий после окончания.
- Замена одних звуков другими в одной и той же части слова.
- Наименьшая значимая часть слова.
- Значимая часть слова, которая находится перед корнем и служит для образования слов.
- Главная значимая часть слова.
- Часть изменяемого слова без окончания.
2.
Рефлексия.
1. Что нового узнали на уроке?
2. Расскажите о порядке морфемного разбора слова.
2. Какие части слов могут иметь разный звуковой состав?
4.Приведите примеры чередований при образовании слов.
5. Могут ли чередоваться звонкие и глухие согласные в одной морфеме? Если могут, приведите примеры.
(Звонкие и глухие согласные могут чередоваться: в снегу – снег, бегу-бег)
Домашнее задание
1. Пар.81.
2. Упр. 416 – устный и письменный разбор слов.
Морфологический разбор глаголов онлайн
Морфологический разбор глаголов онлайнПеречислим характеристики глагола для составления морфологического разбора.
- Общее значение: означает действие или состояние предмета.
- Вопрос: что делать? что сделать? (ставится в нужной форме).
- Начальная форма: неопределённая форма.
- Морфологические признаки:
Постоянные признаки: вид, спряжение, переходность.
Непостоянные признаки: наклонение, число, время, лицо, род. - Синтаксическая роль:
Инфинитив — любой член предложения;
Личные формы — сказуемое.
План разбора
- Часть речи. Общее значение.
- Морфологические признаки:
- Начальная форма.
- Постоянные признаки: вид, спряжение, переходность.
- Непостоянные признаки: наклонение, число, время (если есть), лицо (если есть), род (если есть).
- Синтаксическая роль.
Пример разбора
Дано предложение: «Будущее принадлежит людям честного труда» (М. Горький).
Задание: разобрать слово принадлежит.
- Принадлежит — глагол.
- Морфологические признаки:
- Начальная форма — принадлежать.
- Постоянные признаки: несовершенный вид, непереходный, второе спряжение.
- Непостоянные признаки: изъявительное наклонение, единственное число, 3-е лицо, настоящее время.
- В предложении является сказуемым (что делает?): принадлежит.
Наш сайт делает морфологический разбор глаголов. Введите слово в текстовое поле и нажмите кнопку.
Слова с буквой ё пишите через букву ё (не через е!). Пчелы и пчёлы или слезы и слёзы — разные слова, имеющие разные морфологические разборы.
morphologyonline.ru — морфологический разбор слов
Морфологический разбор слова. Онлайн сервис Текстовод.Морфология
{{ info }}
Выполнить{{ text }} — {{ item.tag }}
Начальная форма — {{ item.normal_form }}
Формы слова
{{ lexem[0] }} — {{ lexem[1] }}
Морфологический разбор слова — это анализ его морфологических признаков.
Морфология — это раздел науки о языке, изучающий слово как часть речи.
Данный сервис поможет определить часть речи любого русского слова и его морфологические признаки онлайн.
Напечатайте проверяемое слово в форме поиска и нажмите «Выполнить».
Возле анализируемого слова вы увидите сокращения морфологических признаков.
Расшифровка всех обозначений находится в Словаре сокращений (ссылка внизу, сразу после разбора).
После указания морфологических признаков, программа ставит слово в начальную форму.
Затем предоставляются варианты форм слова.
После этого приводится морфологический разбор каждой формы слова по отдельности.
Учитывайте, что буквы е и ё — это две разные буквы, соответственно, разбор слов с этими буквами будет разным.
Морфологический разбор всех слов начинается с определения части речи.
Далее порядок отличается.
Разбор существительного.
1. Поставить слово в именительном падеже, единственном числе, т.е. в начальную форму.
2. Затем указать постоянные признаки слова:
- разряд по значению (нарицательное или собственное),
- одушевлённое или неодушевлённое,
- склонение, род, число.
3. После этого, определить непостоянные признаки разбираемого слова: падеж и число.
Выполним разбор слова текстовод.
СУЩ. — существительное,
Од. — одушевлённое,
мр. — мужской род,
Ед. — единственное число,
им. — именительный падеж.
Начальная форма — текстовод.
Формы слова:
текстовод — СУЩ,од,мр ед,им
текстовода — СУЩ,од,мр ед,рд
текстоводу — СУЩ,од,мр ед,дт
текстовода — СУЩ,од,мр ед,вн
текстоводом — СУЩ,од,мр ед,тв
текстоводе — СУЩ,од,мр ед,пр
текстовода — СУЩ,од,мр мн,им,разг
текстоводы — СУЩ,од,мр мн,им
текстоводов — СУЩ,од,мр мн,рд
текстоводам — СУЩ,од,мр мн,дт
текстоводов — СУЩ,од,мр мн,вн
текстоводами — СУЩ,од,мр мн,тв
текстоводах — СУЩ,од,мр мн,пр.
Разбор прилагательного.
1. Найти начальную форму слова. Для этого необходимо поставить слово в именительный падеж, мужской род единственного числа.
2. Затем определить постоянный признак слова — разряд.
3. После найти непостоянные признаки: степень сравнения, форма, число, падеж и род.
Пример: лучший.
ПРИЛ. — прилагательное,
Превосх. — превосходная степень,
Кач. Качественный разряд,
мр. — мужской род,
ед.- единственное число,
им. — именительный падеж.
Начальная форма — хороший.
Формы слова:
хороший — ПРИЛ,кач мр,ед,им
хорошего — ПРИЛ,кач мр,ед,рд
хорошему — ПРИЛ,кач мр,ед,дт
хорошего — ПРИЛ,кач од,мр,ед,вн
хороший — ПРИЛ,кач неод,мр,ед,вн
хорошим — ПРИЛ,кач мр,ед,тв
хорошем — ПРИЛ,кач мр,ед,пр.
И т. д.
Разбор глагола.
1. Записать слово в начальной форме — инфинитиве.
2. Затем определить постоянные признаки слова: вид, спряжение, переходность, возвратность.
3. После найти непостоянные признаки слова: число, наклонение, время, род, лицо.
Пример: помогает.
ГЛ. — глагол.
Несов. — несовершенный вид,
Неперех. — непереходный,
Ед — единственное число,
3л — третье лицо,
Наст. — настоящее время,
Изъяв. — изъявительное наклонение.
Начальная форма — помогать.
Формы слова:
помогать — ИНФ,несов,неперех
помогаю — ГЛ,несов,неперех ед,1л,наст,изъяв
помогаем — ГЛ,несов,неперех мн,1л,наст,изъяв
помогаешь — ГЛ,несов,неперех ед,2л,наст,изъяв.
И т.д.
Разбор причастия.
1. Поставить слово в начальную форму.
2. Указать разряд причастия.
3. Затем написать признаки: форма, число, род, падеж, время, вид, возвратность.
Пример: думающий.
ПРИЧ. — причастие.
Несов. — несовершенный вид,
Неперех. — непереходное,
Наст. — настоящее время,
Действ. — действительный залог,
мр. — мужской род,
ед. — единственное число,
им. — именительный падеж.
Начальная форма — думать.
Формы слова:
думать — ИНФ,несов,неперех
думаю — ГЛ,несов,неперех ед,1л,наст,изъяв
думаем — ГЛ,несов,неперех мн,1л,наст,изъяв
думаешь — ГЛ,несов,неперех ед,2л,наст,изъяв
И т. д.
Разбор деепричастия.
1. Поставить слово в начальную форму.
2. Определить постоянные признаки: возвратность, вид, переходность и спряжение.
3. Затем определить непостоянный признак — неизменяемость.
Например: улыбнувшись.
ДЕЕПР — деепричастие,
Сов. — совершенный вид,
Неперех.- непереходный,
Прош — прошедшее время,
*ши — деепричастие на -ши.
Начальная форма — улыбнуться.
Формы слова:
улыбнуться — ИНФ,сов,неперех
улыбнулся — ГЛ,сов,неперех мр,ед,прош,изъяв
И т. д.
Разбор местоимения.
1. Определить постоянные признаки: разряд, соотношение с другой частью речи, лицо, число.
2. Указать переменные признаки: род и падеж местоимения.
Пример: они.
МС. — местоимение-существительное,
3л — третье лицо,
Анаф. — Анафорическое (местоимение),
Мн — множественное число,
Им — именительный падеж.
Начальная форма — они.
Формы слова:
они — МС,3л,Анаф мн,им
их — МС,3л,Анаф мн,рд
Разбор наречия.
1. Определяются следующие признаки: разряд, степень сравнения, неизменяемость.
Пример: зачем.
Н. — наречие,
Вопр — вопросительное,
Предк? — может выступать в роли предикатива
Начальная форма — зачем.
Разбор частиц.
Самый короткий разбор бывает у частиц.
У этих частей речи указываются начальная форма, неизменяемость, разряд и функция.
Смотрите сами: только.
ЧАСТ. — частица
Начальная форма — только.
Формы слова:
только — ЧАСТ
тока — ЧАСТ искаж.
Слова «провёл» морфологический и фонетический разбор
Объяснение правил деление (разбивки) слова «провёл» на слоги для переноса.
Онлайн словарь Soosle.ru поможет: фонетический и морфологический разобрать слово «провёл» по составу, правильно делить на слоги по провилам русского языка, выделить части слова, поставить ударение, укажет значение, синонимы, антонимы и сочетаемость к слову «провёл».
Слоги в слове «провёл» деление на слоги
Количество слогов: 2
По слогам: про-вёл
Ударение в слове «провёл»
Провё́л — ударение падает на 2-й слог
Фонетический разбор слова «провёл» на буквы и звуки (Звуко-буквенный)
Буква | Звук | Характеристики звука | Цвет |
---|---|---|---|
П | [п] | согласный, глухой парный, твёрдый, шумный | П |
р | [р] | согласный, звонкий непарный (сонорный), твёрдый | р |
о | [а] | гласный, безударный | о |
в | [в’] | согласный, звонкий парный, мягкий | в |
ё | [`о] | гласный, ударный | ё |
л | [л] | согласный, звонкий непарный (сонорный), твёрдый | л |
Число букв и звуков:
На основе сделанного разбора делаем вывод, что в слове 6 букв и 6 звуков.
Буквы: 2 гласных буквы, 4 согласных букв.
Звуки: 2 гласных звука, 4 согласных звука.
Сочетаемость слова «провёл»
1. проводить кого-либо взглядом
2. провести время
3. провести ночь
4. (полная таблица сочетаемости)
Значение слова «провёл»
ПРОВЕСТИ́ , -веду́, -ведёшь; прош. провёл, -вела́, -ло́; прич. прош. прове́дший; прич. страд. прош. проведённый, -дён, -дена́, -дено́; сов. (несов. проводить1). 1. перех. Ведя, помочь или заставить пройти. Провести под уздцы лошадь. (Малый академический словарь, МАС)
Как правильно пишется слово «провёл»
Орфография слова «провёл»Правильно слово пишется:
Нумерация букв в слове
Номера букв в слове «провёл» в прямом и обратном порядке:
Как разобрать слово по составу
Давая задание разобрать слово по составу, многие учителя сталкиваются с тем, что не все дети справляются с ним правильно и быстро. На самом деле алгоритм этой процедуры довольно прост. У школьников важно изначально создать эту способность, чтобы потом у них не было проблем.
Разложение слова по композиции означает выделение незначительных частей. Возможность выполнить это действие пригодится при усвоении множества правил правописания.Основные методы — это выбор форм, а также поиск однокоренных и однокоренных слов. Рекомендуется при выделении той или иной морфемы определять ее грамматическое значение.
Перед тем, как разбирать слово по составу, необходимо определить, к какой части речи оно относится. Это необходимо сделать для того, чтобы понять, переменный он или нет (в последнем случае это не закончится). Затем выделяется основа слова. В таких частях речи, как междометие, наречие или отговорка концовки нет и вообще не отмечается.Если якобы возможно, но этого нет в слове (например, мост), то обозначается как «ноль». Остальное называют «базой». Чтобы различить конец, слово меняется (существительные по падежу, прилагательные по роду и т. Д.).
В основе слова лежит его лексическое значение. Из него, в свою очередь, выделяются остальные части. Основная лексическая нагрузка лежит в основе. Это неизменяемая деталь, считающаяся основной. Группы слов, имеющих один и тот же корень, называются однокорневыми.Например: растение, растение, дочернее растение и т. Д.
Если вы посмотрите на слово «подготовка» по составу, то увидите, что конец здесь — морфема -а, корень-готов-для-нас. Далее нужно обратить внимание на суффикс и префикс. Стоит отметить, что они различаются в основном в зависимости от части речи. Чтобы их идентифицировать, необходимо выбрать группу одноструктурных слов.
Итак, для нашего существительного можно взять такие примеры, как «стоять», «подсказка» и т. Д.Приставка считается важной частью.Он используется для образования слов, имеющих разное значение.
Суффиксы находятся после корня. Существительное «подготовка» — это -k-. Эта часть служит для образования нового слова или его формы.
Следует отметить, что в некоторых случаях может быть несколько корней, например пара-о-ход, верт-о-год и т. Д.
В других ситуациях слово может быть образовано с помощью нескольких префиксов или суффиксы.
Они должны быть выделены. Если вы не можете разобрать слово по составу, сложно еще раз вернуться к тому, какая это часть речи.Ведь для большинства групп характерны их морфемы. Стоит упомянуть и постфиксную часть слова, которая встречается в конце глаголов (-a, -a, -e) и некоторых местоимений (-or, -that).
Он не относится к флексиям (окончаниям). В школьных учебниках постфикс называется суффиксом и обозначается таким же знаком. Например, в слове «смеялся» будет окончание -a- («смеялся», «смеялся»).
Postfix в данном случае. При разборе этого слова необходимо не забыть включить его в основу.
(PDF) Состав таблицы синтаксического анализа
22. Карделли, Л., Маттес, Ф., Абади, М .: Расширяемый синтаксис с лексической областью видимости. SRC Research
Отчет 121, Исследовательский центр цифровых систем, Пало-Альто, Калифорния (февраль 1994 г.)
23. Кнут Д.Э .: О переводе языков слева направо. Информация и контроль 8 (6)
(декабрь 1965) 607–639
24. Ахо, А.В., Джонсон, С.К .: Анализ LR. ACM Computing Surveys 6 (2) (1974) 99–124
25.Ахо, А.В., Сетхи, Р., Ульман, Дж .: Компиляторы: принципы, методы и инструменты. Аддисон Уэсли,
Рединг, Массачусетс (1986)
26. Грун, Д., Джейкобс, К.Дж.Х .: Методы синтаксического анализа — Практическое руководство. Эллис Хорвуд, Аппер
,Сэдл-Ривер, Нью-Джерси, США (1990)
27. Джонстон, А., Скотт, Э .: Разбор LR с модифицированной редукцией для создания прототипов на языке
. В: 35th Annual Hawaii International Conference on System Sciences
(HICSS’02), Washington, DC, USA, IEEE Computer Society Press (2002) 282
28.Хопкрофт, Дж. Э., Мотвани, Р., Уллман, Дж. Д .: Введение в теорию автоматов, языки и вычисления
(3-е издание). Аддисон-Уэсли, Бостон, Массачусетс, США (2006)
29. Лесли, Т .: Эффективные подходы к построению подмножеств. Магистерская диссертация, Университет Ватерлоо,
Ватерлоо, Онтарио, Канада (1995)
30. Ван Ноорд, Г .: Обработка эпсилон-движений при построении подмножеств. Компьютерная лингвистика
26 (1) (2000) 61–76
31. Зайдель, Р., Арагон, К.Р .: Рандомизированные деревья поиска. Algorithmica 16 (4/5) (1996) 464–497
32. ДеРемер, Ф .: Простые LR (k) грамматики. Коммуникации ACM 14 (7) (1971) 453–460
33. Джонстон, А., Скотт, Э., Экономопулос, Г .: Оценка алгоритмов синтаксического анализа GLR. Science of
Компьютерное программирование 61 (3) (2006) 228–244
34. ДеРемер, Ф., Пеннелло, Т.Дж .: Эффективное вычисление LALR (1) упреждающих множеств. В: CC ’79,
New York, NY, USA, ACM Press (1979) 176–187
35.Tarjan, R.E .: поиск в глубину и алгоритмы линейного графа. SIAM Journal on Computing
1 (2) (1972) 146–160
36. Ева, Дж., Курки-Суонио, Р .: О вычислении транзитивного замыкания отношения. Acta Informatica
8 (4) (1966) 303–314
37. Нуутила, Э .: Эффективное вычисление переходного замыкания в больших орграфах. Кандидатская диссертация, Хельсинки
Технологический университет (1995)
38. Бравенбоер, М .: Упражнения в свободном синтаксисе. Определение синтаксиса, анализ и ассимиляция
языковых конгломератов.Докторская диссертация, Утрехтский университет, Утрехт, Нидерланды (
,, 2008 г.)
39. Бравенбор, М., Тантер, Э., Виссер, Э .: Декларативное, формальное и расширяемое определение синтаксиса
для AspectJ — A случай для разбора обобщенного LR без сканирования. В: OOPSLA’06, ACM Press
(2006)
40. Гримм, Р .: Лучшая расширяемость за счет модульного синтаксиса. In Cook, W.R., ed .: PLDI’06, ACM
Press (июнь 2006)
41. Ван Вик, Э., Швердфегер, А .: Контекстно-зависимое сканирование для синтаксического анализа расширяемых языков.
[47]
42. Эрли, Дж .: Эффективный контекстно-свободный алгоритм синтаксического анализа. Коммуникации ACM 13 (2)
(1970) 94–102
43. Тратт, Л .: Язык программирования Converge. Технический отчет TR-05-01, Департамент
Компьютерные науки, Королевский колледж Лондона (февраль 2005 г.)
44. Колбли Д.М.: Реализация расширяемого языка. Кандидатская диссертация, Техасский университет в Остине
(декабрь 2002 г.)
45. Бейкер, Дж., Се, В .: Maya: расширение синтаксиса множественной диспетчеризации в java.В: PLDI ’02, ACM
Press (2002) 270–281
46. de Rauglaudre, D .: Camlp4 Reference Manual. (Сентябрь 2003 г.)
47. Лаволл, Дж., Изд .: Генеративное программирование и разработка компонентов, Шестая международная конференция
, GPCE 2007, Нью-Йорк, Нью-Йорк, США, ACM Press (октябрь 2007 г.)
Frontiers | ULTRA: универсальная грамматика как универсальный синтаксический анализатор
Введение
Одним из наиболее значительных недавних достижений лингвистической теории является появление высококачественных наборов данных по всему спектру межъязыковых вариаций.В прошлом генеративные исследования обычно полагались на детальное изучение одного или нескольких языков для выявления синтаксических механизмов. Хотя этот подход, безусловно, плодотворен, накопление информации о большом количестве языков открывает новые возможности для улучшения понимания.
В порождающей грамматике значительное внимание уделяется рекурсии как (или даже ) фундаментальному свойству языка (обсуждение см. В Berwick and Chomsky, 2016).Это формализовано в основной операции под названием Merge, объединяющей два синтаксических объекта (в конечном итоге построенных из лексических элементов) в набор, содержащий оба. Рекурсия следует из способности Merge применять к собственному выводу. Merge также фиксирует тот важный факт, что предложения имеют внутреннюю структуру (составные части в квадратных скобках), причем каждый уровень соответствует приложению Merge.
Вопреки этой концепции, я утверждаю, что концептуальной ошибкой является рассмотрение предложений как групп (будь то наборы или что-то еще) лексических элементов.Ошибка заключается в представлении о лексических единицах как о связанных единицах, существующих на одном уровне. Это также приводит к мысли о предложениях как о одноуровневых представлениях. Проще говоря, слова — это не вещей ; они представляют собой пару процессов, протянутых во времени. В контексте понимания релевантными процессами являются распознавание слова и интеграция его значения в интерпретацию. Я развиваю новый взгляд на структуру предложений с точки зрения этих двух типов процессов.Важно отметить, что нетривиальные отношения определяют их относительную последовательность: одно слово может встречаться раньше, чем другое в поверхностном порядке, но его значение может быть интегрировано позже. Рассмотрение предложений как единых, вневременных представлений, построенных на непроницаемых лексических атомах, оставляет нас неспособными уловить фундаментально задействованные временные явления, в которых два аспекта каждого слова не связаны вместе, а процессы для разных слов переплетаются.
В этой статье предлагается новая модель грамматических механизмов, получившая название ULTRA (Универсальный реактивный автомат с линейным преобразованием).В локальных синтаксических доменах, формирующих расширенную проекцию лексического корня (такого как глагол или существительное), ULTRA использует алгоритм стековой сортировки Кнута (1968) для непосредственного сопоставления поверхностных порядков слов с лежащей в основе базовой структурой. Сопоставление успешно только для 213 приказов избегания. Это интригующий результат, поскольку избегание 213, возможно, ограничивает вариацию нейтрального порядка слов в разных языках в различных синтаксических областях. Хотя локальные звуковые и смысловые репрезентации в этой модели являются последовательностями, иерархическая структура, тем не менее, возникает в динамическом действии отображения.Обнаруженные здесь структуры в квадратных скобках, хотя и эпифеноменальные, очень похожи на структуры, построенные Merge, с некоторыми существенными различиями (возможно, в пользу нынешней теории).
Сортировка по стеку оказалась эффективной процедурой для связывания порядка слов и иерархической интерпретации, включая линеаризацию, смещение, композицию и помеченные скобки. Теория предлагает реализацию как процесс исполнения в реальном времени. Осознание этого значительно меняет границы между производительностью и компетенцией.Примечательно, что ULTRA не требует никаких параметров, зависящих от языка; инвариантный алгоритм служит грамматическим устройством для всех языков. Проще говоря, я предполагаю, что Universal Grammar — это универсальный синтаксический анализатор.
Тем не менее, стековая сортировка — это слишком ограниченный механизм для описания всех явлений человеческого синтаксиса. Остается незавершенным три вида эффектов: неограниченная рекурсия, ненейтральный порядок и существование явно различных языков. Более того, понимание стековой сортировки как системы обработки сталкивается с двумя очевидными проблемами: это однонаправленный синтаксический анализатор, который не является тривиально обратимым для производства; и это противоречит убедительным доказательствам пословной постепенности в понимании.
Хотя построение полной модели синтаксиса и обработки выходит далеко за рамки данной статьи, проблемы, возникающие при построении модели синтаксического анализа как грамматики на сортировке стека, требуют рассмотрения. Я обращаюсь к различию между реактивными и предсказательными процессами, рассматривая стековую сортировку как универсальную реактивную процедуру. Отдельный прогностический модуль играет решающую роль в производстве и в появлении четких, относительно жестких порядков слов. Прогнозирование также помогает согласовать ULTRA с инкрементной интерпретацией.Я обращаюсь к свойствам памяти для решения дальнейших проблем, предполагая, что первичная память (отличная от памяти недавнего времени, лежащей в основе сортировки стека) является источником другого кластера синтаксических свойств, включая перемещение на большие расстояния, пересекающиеся зависимости и специальный синтаксис «левая периферия». Наконец, я предполагаю, что эпизодическая память — независимо иерархическая по структуре у людей — играет ключевую роль в лингвистической рекурсии.
Данная статья имеет следующую структуру.В разделе Linear Base утверждается, что «базовая» структура внутри каждого локального синтаксического домена представляет собой последовательность. Раздел * 213 в «Нейтральном порядке слов» исследует обобщение, согласно которому «213-избегание» ограничивает возможности нейтрального по отношению к информации порядка слов в разных языках. Раздел «Сортировка стека как грамматический механизм» предлагает процедуру сортировки стека для выявления «избегания 213» в порядке слов. Раздел Stack-Sorting: Linearization, Displacement, Composition и Labeled Brackets показывает, как дальнейшие синтаксические эффекты следуют из сортировки по стеку.Раздел Сравнение с существующими учетными записями Universal 20 сравнивает ULTRA с существующими учетными записями избегания 213 в порядке слов, уделяя особое внимание Universal 20. Раздел Universal Grammar as Universal Parser преследует реализацию стековой сортировки в реальном времени. В разделе «Возможные расширения более полной теории синтаксиса» рассматриваются проблемы, связанные с принятием стековой сортировки в качестве ядра универсальной грамматики, и приводится набросок некоторых возможных расширений. Раздел Заключение завершается.
Линейное основание
Синтаксическая комбинация может принимать разные формы.Возникает точка зрения, согласно которой сочетание в значительной степени поддерживает отношения между головой и дополнением (Starke, 2004; Jayaseelan, 2008). В этом контексте термин «голова» имеет как минимум два разных значения. Во-первых, в любой комбинации двух синтаксических объектов один является «более важным» по отношению к составному значению. Назовем это понятие головы корнем , отметив, что в расширенных проекциях существительных и глаголов лексическое существительное или корень глагола является семантически доминантным. Другой смысл головы касается того, какой элемент определяет комбинаторное поведение композиции; назовем это понятие головы меткой .
В более старых теориях структуры фраз два смысла головы (корень и метка) сходились в одном элементе; существительное, например, в сочетании со всеми его модификаторами в существительной фразе. Таким образом, головокружение соотносится с иерархическим доминированием; корень проецировал свой ярлык над своими иждивенцами. Для иллюстрации комбинация прилагательного и существительного, например, red book , будет представлена следующим образом.
Этот традиционный вывод о взаимосвязи зависимости и иерархии опровергнут современной синтаксической картографией (Rizzi, 1997; Cinque, 1999 и последующие работы).Картографические подходы предполагают, что синтаксическая комбинация следует строгой, кросс-лингвистической однородной иерархии внутри каждой расширенной проекции. Эта иерархия включает в себя последовательность функциональных глав, лицензионную комбинацию с различными модификаторами в строгом порядке. Фраза красных книг представлена следующим образом.
Здесь прилагательное — это спецификатор специализированного функционального заголовка (F), который маркирует композицию, определяя ее комбинаторное поведение. В картографических изображениях головы равномерно на ниже, чем на их иждивенцев, которые появляются выше по позвоночнику.
Вопросы возникают по поводу этих представлений, которые постулируют обилие невысказанного материала. Любопытное наблюдение заключается в том, что функциональные заголовки и их спецификаторы явно не встречаются вместе, как это формализовано в обобщенном двойном фильтре компаундирования Купмана (2000).
Старк (2004) развивает наблюдение Купмана дальше, утверждая, что заголовки и спецификаторы не встречаются одновременно, потому что они представляют собой токенов одного типа , конкурирующих за одну позицию. Старке преобразовывает картографический корешок в абстрактную функциональную последовательность ( fseq ), позиции которой могут быть обозначены как лексическим, так и фразовым материалом.Следуя концепции Старке, комбинация прилагательного и существительного будет представлена, как показано ниже.
Мы снова изменили традиционные выводы об иерархии глав и иждивенцев. Тем не менее, понятие корня (выделение существительного) по-прежнему имеет решающее значение, поскольку модификаторы расположены в иерархическом порядке, продиктованном и fseq.
Синтаксическая комбинация этого типа является последовательной в пределах каждой расширенной проекции. Эти «базовые» последовательности кодируют композицию «снизу вверх», поэтому естественно упорядочить последовательность таким же образом (снизу вверх).База (т.е. fseq, картографический корешок) широко считается единообразной для разных языков и выражает «тематическое», информационно-нейтральное значение (в отличие от дискурсивно-информационной структуры).
Грамматика, согласно любой теории, определяет формальное отображение, связывающее звук и значение (точнее, внешнюю и внутреннюю формы, допускающие не слуховые модальности). Эта спецификация может принимать разные формы. Последовательное представление основы позволяет очень просто сформулировать звуково-смысловое отображение.Эта переформулировка дает принципиальное описание класса универсалий порядка слов. Более того, хотя интерфейсные объекты (порядок слов и базовые деревья), участвующие в отображении, являются последовательностями, заключенная в скобки иерархическая структура возникает как динамический эффект.
Существуют различные способы концептуализации взаимосвязи между базовым и поверхностным порядком слов. Обычное мнение состоит в том, что база упорядочивает входные данные до производных, давая поверхностный порядок слов в качестве выходных данных. Эта направленность подразумевается в терминах, используемых для описания отношения иерархия-порядок: линеаризация , экстернализация и т. Д.В этой статье мы придерживаемся другой точки зрения, согласно которой порядок слов на поверхности является входными данными для алгоритма, который пытается собрать основу в качестве выходных данных. Примечательно, что единственные исходные данные, которые сходятся на единой основе в рамках этого процесса, — это 213-избегание; порядок слов, содержащих 213, приводит к отклонению от нормы.
* 213 В нейтральном порядке слов
213-избегание, возможно, улавливает возможности нейтрального по отношению к информации порядка слов в различных синтаксических областях, в разных языках. Под 213-избеганием я подразумеваю запрет на порядок поверхностей… b… a… c …, для элементов a ≫ b ≫ c , где ≫ указывает c-команду в стандартных древовидных представлениях базы ( эквивалентно доминирование в деревьях Старке).Другими словами, нейтральные порядки слов, кажется, избегают последовательности элементов от среднего до высокого-низкого (под) из одного fseq. Элементы, образующие этот запрещенный контур, не обязательно должны быть смежными, в порядке поверхности или в основании fseq.
213-избегание, как широко распространено, ограничивает возможности упорядочивания кластеров глаголов, хорошо известных в западногерманском языке (см. Обзор в Wurmbrand, 2006). Обширный обзор голландских диалектов, проведенный Barbiers et al. (2008), обнаружил очень мало примеров этого порядка; Немецкие диалекты, кажется, тоже избегают этого порядка.Между тем Zwart (2007) анализирует порядок 213 в кластерах голландских глаголов как включающий экстрапозицию последнего элемента.
Наиболее изученной областью, поддерживающей избегание 213 в порядке слов, является Universal 20 Гринберга, описывающая порядок именных фраз.
«Когда какие-либо или все элементы (указательные, числительные и описательные прилагательные) предшествуют существительному, они всегда находятся в указанном порядке. Если они следуют, то порядок либо тот же, либо полная противоположность »(Greenberg, 1963, стр. 87).
Последующие работы улучшили эту картину.Cinque (2005) сообщает, что только 14 из 24 логически возможных порядков этих элементов засвидетельствованы как информационно-нейтральные порядки (Таблица 1).
Таблица 1 . Возможный порядок именных фраз. Cinque (2005, стр. 319–320) отчет о количестве языков, представленных в каждом порядке, дается числом: 0 = не подтверждено; 1 = очень мало языков; 2 = несколько языков; 3 = много языков; 4 = очень много языков.
Чинкве описывает эти факты с ограничением движения с единой базы.В частности, он предлагает, чтобы все движения перемещали существительное или что-то, что его содержит, влево (раздел «Сравнение с существующими счетами Universal 20» подробно описывает теорию Чинкве и связанные с ней описания). Что запрещено, так это движение остатка.
Порядок именных фраз подчиняется простому обобщению: подтвержденные порядки — это все и только 213 перестановки, избегающие перестановок. Все непроверенные заказы имеют 213 подпоследовательностей. Например, неподтвержденный * Num Dem Adj N содержит подпоследовательности Num Dem Adj … и Num Dem… N , представляющие контуры среднего-высокого-низкого уровня относительно fseq.
Сортировка стека как грамматический механизм
Существует особенно простая процедура, которая отображает порядок слов, избегающих 213, в единую основу, называемая сортировкой стека. Я описываю адаптацию алгоритма сортировки стека Knuth (1968), который использует память «последний пришел — первым вышел» (стек) для сортировки элементов по их относительному порядку в базе. Это частичный алгоритм сортировки: он достигает желаемого результата только для некоторых входных порядков.
(4) S АЛГОРИТМ СОРТИРОВКИ ТАКСИ D ОПРЕДЕЛЕНИЯ
Пока ввод не пуст, I: следующий элемент ввода.
Если я S, Pop. S: элемент наверху стека.
Else Push. x ≫ y: x c-команды y в
база (например, Dem ≫ N).
Пока Stack не пуст, Push: перемещает I из входа
в стек.
Поп. Pop: перемещает S из стека
для вывода.
(4) отображает все и только 213-избегающие порядки слов в 321-подобную иерархию, соответствующую основанию. Заказы, содержащие 213, сопоставляются с отклоняющимся выходом, отличным от базового. По предположению, именно поэтому такие порядки типологически недоступны: они автоматически отображаются в неинтерпретируемом порядке композиции. Это объясняет шаблон Universal 20 (Таблицы 2, 3).
Таблица 2 . Результат стековой сортировки логически возможных порядков из 4 элементов, в формате вход → выход.
Таблица 3 . Вычисления сортировки стека для 4-х порядков.
Проиллюстрируем, как (4) разбирает некоторые порядки именных фраз: Dem-Adj-N, N-Dem-Adj, * Adj-Dem-Num.
(5) Dem-Adj-N: PUSH (Dem), PUSH (Adjust), PUSH (N),
POP (N), POP (Adj), POP (Dem).
(6) N-Dem-Adj: PUSH (N), POP (N), PUSH (Dem), PUSH (Adj),
POP (Настр.), POP (Дем.).
Для аттестованных заказов номинальные категории POP в порядке
(7) * Adj-Dem-N: PUSH (Настр.), POP (Настр.), PUSH (Дем.),
НАЖАТЬ (N), POP (N), POP (Дем).
Для неподтвержденного порядка 213, элементы POP в девиантном порядке *
Это хорошо: (4) сопоставляет подтвержденные заказы с их универсальным значением, одновременно исключая не подтвержденные заказы. Но помимо такого сопоставления, адекватная грамматика должна объяснять другие аспекты знания языка, включая брекетинг поверхностной структуры.Если грамматика рассматривает поверхностные порядки и базовые структуры как последовательности (локально), откуда может взяться такая заключенная в скобки структура?
Сортировка стопкой: линеаризация, смещение, композиция и маркированные скобки
В этом разделе я покажу, что сортировка стека эффективно охватывает линеаризацию, смещение и композицию, а также назначение скобок, однозначно помеченных без поиска. Более того, все это выполняется без параметров, зависящих от языка.
В стандартном («Y-модель») представлении линеаризация и композиция — это отдельные операции интерфейса, интерпретирующие структуры, построенные в автономном синтаксическом модуле с помощью Merge.В ULTRA линеаризация идет в другом направлении, поэтапно загружая в память поверхностный порядок слов и собирая их в порядке композиционной интерпретации.
Смещение — естественное свойство грамматики сортировки стека
Смещение — естественная особенность сортировки стопкой; с одной точки зрения, это основное свойство системы. В стандартных отчетах составляющие, составляющие вместе при интерпретации, должны появляться смежными в поверхностном порядке. Такое расположение вызвано грамматиками фразовой структуры.Смещение, при котором элементы, составляющие вместе, разделяются промежуточными элементами в порядке поверхности, всегда казалось удивительным свойством, требующим объяснения.
В ULTRA все работает иначе. Ключевое предположение представления на основе слияния отвергается: нет уровня представления, охватывающего порядок слов и fseq в унифицированном объекте более высокого порядка. Вместо этого порядок слов и базовая иерархия — это несвязанные последовательности, связанные динамически. Несмежные элементы ввода вполне могут оказаться смежными на выходе.Смещение, а не исключение, является правилом; : каждый элемент в поверхностном порядке «трансформируется», проходя через память перед извлечением для интерпретации.
Скобки и метки без примитивного округа
Алгоритм (4) неявно назначает помеченную структуру в квадратных скобках каждому порядку поверхности, почти точно совпадая со структурами, назначенными такими учетными записями, как Cinque (2005). Явно нажатие (сохранение от порядка слов до стека) соответствует левой скобке, а выталкивание (извлечение из стека для интерпретации) — правой скобке.Эти операции применяются к одному элементу за раз; естественно думать, что этот элемент обозначает соответствующую скобку. См. Таблицу 4, в которой представлены вычисления сортировки стека для всех перестановок поверхностей трехэлементной базы.
Таблица 4 . Вычисления с сортировкой стека для порядков из 3 элементов.
Рассматривая эти скобки, последовательность нажатий и извлечений (хранение и извлечение) для каждого порядка неявно определяет дерево, как показано на рисунке 1. Это так называемые деревья Дика, набор всех упорядоченных корневых деревьев с фиксированным числом. узлов (здесь 4).Сравните их с деревьями бинарного ветвления, назначенными в соответствии с отчетом Чинкве (2005), с неостаточным движением влево, влияющим на основание ветвления вправо (рис. 2). Скобки почти идентичны, как и их ярлыки, но есть некоторые вольности с техническими деталями аккаунта Cinque.
Рисунок 1 . Скобки и соответствующие деревья push-pop для принятых (сортированных по стеку) порядков из трех элементов. Это просто деревья Дика с 4 узлами.
Рисунок 2 .Деревья с бинарным ветвлением для производных аттестованных порядков трех элементов, избегающих перемещения остатков, с соответствующими скобками. Лексический корень (например, N в существительной фразе) показан черным треугольником, а структуры с концом и следом движения представлены двойной ветвью ||. Деревья представлены таким образом, чтобы выделить соответствие с деревьями Дика для этих порядков, полученных в результате сортировки стека.
Если отложить в сторону 321 дерево (а), то деревья Дика представляют собой систематические сжатия без потерь деревьев Чинкве, при этом каждое поддерево, которое является ветвящейся вправо гребенкой в дереве Чинкве, заменено линейным деревом (см. 2008) в дереве Дика.Для этого соответствия, которое сводится к сокращению всех терминалов в двоичном дереве, лексический корень (например, существительное в DP) не должен сокращаться. Элементы из поверхностного порядка связаны с каждым узлом дерева Дика, кроме самого высокого, с линейным порядком чтения слева направо среди сестринских узлов и сверху вниз по унарным ветвящимся путям. Например, для порядка 132 поверхности 1 связан с единственным бинарным ветвящимся узлом в его дереве Дика, 3 и 2 — с его левой и правой дочерними элементами (рис. 3).
Рисунок 3 .Два представления в квадратных скобках 132 порядка поверхности и соответствующие деревья. Слева — структура, найденная при чтении операций сортировки стека в скобках; Элементы поверхности обозначены каждым узлом (кроме самого верхнего, пунктирного). Линейный порядок считывается сверху вниз по унарным ветвящимся путям, а слева направо среди сестринских узлов. В соответствующем двоичном ветвящемся дереве, представляющем его происхождение перемещением (справа) , ярко выраженные элементы идентифицируются только с конечными узлами.
Между тем, порядок 321, которому присвоено троичное дерево путем сортировки стека, имеет два производных, исключающих перемещение остатков. В одном из возможных выводов 3 инвертируют, причем 2 сразу после объединения 2, затем 32 комплекса перемещаются за 1 после объединения 1. В другом возможном выводе сначала объединяется полная базовая структура, затем 23 перемещаются влево, а затем влево перемещается всего 3.
Ключевой эмпирический вопрос заключается в том, демонстрируют ли 321 порядок две отдельные заключенные в скобки структуры, как это позволяют трактовки бинарного ветвления, или только единственная, «плоская» структура, предсказанная здесь.Проблема становится еще более острой для 4 элементов, как в Universal 20, где существует до 5 различных производных слияния для порядка 4321. К счастью, это ( N Adj Num Dem ) является наиболее распространенным порядком именных фраз; будущие исследования должны пролить свет на эту проблему.
Сводка раздела
Stack-sorting захватывает удивительное количество синтаксического механизма, обычно разделенного между различными модулями. В обычном представлении автономный генераторный движок строит составляющие структуры, интерпретируемые на интерфейсах дальнейшими процессами линеаризации и композиции.В ULTRA линеаризация и композиция отражают единую процедуру. Составная структура не является примитивной, но записывает этапы хранения и извлечения, с помощью которых сортировка стека собирает интерпретацию. Это создает структуру поверхности в квадратных скобках, обозначенную соответствующим образом, в значительной степени идентичную структуре в скобках в счетах, постулирующих движение (внутреннее слияние) от единой основы (сформированной внешним слиянием). Однако там, где стандартные теории допускают множественные выводы для некоторых порядков поверхностей (и неоднозначную бинарную ветвящуюся структуру), в настоящем описании назначается уникальная внебинарная скобка.Примечательно, что специфические языковые особенности не играют никакой роли в движении. Смещение обрабатывается автоматически путем сортировки стека и фактически является его основной функцией.
Сравнение с существующими счетами Universal 20
В этом разделе сравнивается учетная запись сортировки стека Universal 20 с существующими учетными записями на основе слияния (Cinque, 2005; Steddy and Samek-Lodovici, 2011; Abels and Neeleman, 2012). Я утверждаю, что учетная запись сортировки стека проще, при этом избегая проблем, которые возникают в каждой из этих существующих альтернатив.
Счет Чинкве (2005)
Cinque предлагает кросс-лингвистически однородную базовую иерархию, отражающую фиксированный порядок внешнего слияния. Он предполагает, что движение (внутреннее слияние) происходит равномерно влево, в то время как основание ветвится вправо, в соответствии с LCA Кейна (1994). Он оговаривает, что остаточное движение в именной фразе запрещено: каждое движение влияет на существительное или на составляющую, содержащую его. Его базовая структура для именной группы — (8).
Открытые модификаторы — это спецификаторы выделенных функциональных глав (например,г., X 0 ), ниже договорные фразы, предусматривающие посадочные площадки для передвижения. Эта структура и его предположения о движении выводят все и только подтвержденные приказы. Похожий на английский заказ Dem-Num-Adj-N поверхности без движения; все другие порядки включают некоторую последовательность движений NP или что-то, что ее содержит.
Счет Абельса и Нилмана (2012)
Abels и Neeleman (2012) модифицируют анализ Cinque, отбрасывая элементы, введенные для соответствия LCA (включая согласованные фразы и специальные функциональные главы).Они утверждают, что LCA не играет объяснительной роли; все, что требуется, — это движение влево, а остаточное движение запрещено. Они допускают свободную линеаризацию сестринских узлов, используя значительно более простую базовую структуру (9). Они опускают метки для нетерминальных узлов как не относящиеся к их анализу (Abels and Neeleman, 2012: 34).
По их теории, восемь подтвержденных приказов могут быть получены без движения, изменяя линейный порядок сестер. Остальные подтвержденные заказы требуют движения влево без остатка.В принципе, их система допускает расширенный набор выводов Чинкве (2005); некоторые порядки могут быть получены путем выбора линеаризации или перемещения. Однако, ограничивая внимание строго необходимыми операциями и предполагая, что свободная линеаризация проще, чем перемещение, их вывод обычно проще, чем у Cinque.
Рассказ Стедди и Самек-Лодовичей (2011)
Стедди и Самек-Лодовичи (2011) предлагают еще один вариант анализа Чинкве (2005).Они предлагают теоретико-оптимальное объяснение, сохраняя базовую структуру Чинкве (8). Линейный порядок регулируется набором ограничений Align-Left (10), по одному для каждого открытого элемента.
(10) а. N-L — Выровнять (NP, L, AgrWP, L)
Совместите левый край NP с левым краем AgrWP.
г. A-L — Выровнять (AP, L, AgrWP, L)
Совместите левый край AP с левым краем AgrWP.
г. NUM-L — Выровнять (NumP, L, AgrWP, L)
Выровняйте левый край NumP с левым краем AgrWP.
г. DEM-L — Выровнять (DemP, L, AgrWP, L)
Совместите левый край DemP с левым краем AgrWP.
(Из Стедди и Самек-Лодовичи, 2011: 450).
Эти ограничения выравнивания вызывают нарушение для каждого явного элемента или трассы, отделяющей соответствующий элемент от левого края домена, и варьируются в зависимости от языка. Подтвержденные заказы являются оптимальными кандидатами при некотором ранжировании ограничений. Непроверенные заказы исключаются, потому что они «гармонически ограничены»: какой-либо другой кандидат допускает меньше нарушений более высокого ранга при любом ранжировании ограничений.Таким образом, они могут отказаться от ограничений передвижения, принятых Чинкве (2005) и Абельсом и Нилманом (2012). Вместо этого левосторонний, не остаточный характер движения выпадает из принципов выравнивания.
Проблемы с существующими учетными записями
Хотя эти учетные записи различаются в деталях, у них есть некоторые проблемные особенности. Во-первых, все они отражают шаблон порядка слов на трех уровнях объяснения: (i) единообразная базовая структура, (ii) синтаксическое движение и (iii) принципы линеаризации.Во всех трех учетных записях (i) описывает порядок внешнего слияния. Детали (ii) и (iii) различаются в зависимости от счета. Для Чинкве (2005 г.) и Стедди и Самек-Лодовичи (2011 г.) все заказы, кроме Dem-Num-Adj-N , связаны с движением; Abels и Neeleman (2012) требуют перемещения только для шести подтвержденных заказов. Что касается линеаризации, Cinque (2005) использует LCA Кейна (1994); Абельс и Нилман (2012) имеют движение равномерно влево, но сестры, генерируемые базой, свободно линеаризуются на основе специфики языка; У Стедди и Самек-Лодовичи (2011) есть ранжирование ограничений для конкретного языка.
Все эти учетные записи требуют разных грамматик для разных порядков. В системе Cinque (2005) необходимо изучить особенности, управляющие определенными движениями. То же самое верно для Abels и Neeleman (2012) с дополнительным изучением порядка для сестринских узлов. Стедди и Самек-Лодовичи (2011) требуют изучения ранжирования ограничений, которое дает начало каждому порядку. Таким образом, все эти отчеты сталкиваются с проблемами, связанными с языками, допускающими свободу порядка в ДП; по сути, они должны учитывать недоопределенные или конкурирующие грамматики, чтобы фиксировать различные порядки.
Наконец, все эти отчеты имеют некоторую структурную или грамматическую двусмысленность для некоторых порядков. Для Cinque (2005) одна из разновидностей двусмысленности возникает при выборе того, следует ли переместить функциональную категорию или фразу «Соглашение», в которую она встроена; у этого выбора нет явного рефлекса. Хотя его теория резко ограничивает количество и место посадки возможных перемещений, эти ограничения несколько искусственны; Немногое существенное изменилось бы, если бы мы постулировали дополнительные тихие функциональные уровни для выполнения дальнейших движений или разрешили использование нескольких спецификаторов.В пределе это позволяет использовать весь спектр неоднозначных производных, обсуждаемых в разделе Stack-Sorting: Linearization, Displacement, Composition, and Labeled Brackets. Подход Абельса и Нилмана (2012) допускает эту двусмысленность среди различных производных движений, а также порождение множества порядков посредством перемещения или переупорядочения сестринских узлов. Наконец, Стедди и Самек-Лодовичи (2011) сталкиваются с другой проблемой неоднозначности: некоторые порядки согласуются с множественным ранжированием ограничений (таким образом, множественными грамматиками).
Сравнение со счетом сортировки стека
Счетчик с сортировкой по стеку лучше справляется с этими проблемами. Вместо постулирования отдельных уровней принципов основы, движения и линеаризации соответствующий механизм реализуется в рамках одного алгоритмического процесса. Алгоритм сортировки универсален, он избегает специфичных для языка функций для управления движением, упорядочивания дочерних узлов или ограничений выравнивания рангов. Такая теория идеально подходит для объяснения феномена свободного порядка слов.Кроме того, каждый заказ вызывает уникальную последовательность операций хранения и извлечения, отслеживая уникальный брекетинг. В доменах, характеризующихся нейтральным порядком слов и одним fseq, нет ложной структурной или грамматической двусмысленности для любого порядка слов.
Универсальная грамматика как универсальный синтаксический анализатор
В этом разделе развивается точка зрения, согласно которой сортировка стека может стать основой для инвариантного механизма производительности, реализующего универсальную грамматику как универсальный синтаксический анализатор. Это изменяет традиционные выводы о компетенции и успеваемости, обеспечивая при этом новое представление о том, что такое грамматика.
Переосмысление компетенции и производительности
В генеративных счетах существует фундаментальное разделение между компетенцией и производительностью (Chomsky, 1965). Компетенция включает в себя знание языка, рассматриваемое как абстрактное вычисление, определяющее структурную декомпозицию бесконечного числа предложений. Отдельные системы производительности получают доступ к знаниям системы компетенций во время обработки в реальном времени. С точки зрения трехуровневого описания систем обработки информации Марра (1982), компетентность соответствует высшему, вычислительному уровню, определяя , что делает система, и , почему, .Производительность довольно слабо соответствует нижнему, алгоритмическому уровню, описывая, как вычисления выполняются, шаг за шагом.
Конечно, иерархия Марра применима к обработке информации на языке в рамках данной теории, как и любой другой. Однако разделение труда между этими компонентами здесь существенно перерисовано, и гораздо больше бремени объяснения ложится на производительность. Существенное отличие состоит в том, что в ULTRA заключенная в скобки структура не входит в компетенцию.Вместо этого такая структура возникает во взаимодействии компетенции с алгоритмом сортировки стека во время синтаксического анализа в реальном времени. Знания, приписываемые грамматике компетенций, проще, включая врожденный fseq в качестве основного компонента. В некотором смысле это согласуется с взглядами недавней работы Хомского, в которой компетенция фундаментально ориентирована на вычисление интерпретаций с экстернализацией «вспомогательными».
Универсальный синтаксический анализатор
Новым требованием ULTRA является то, что существует единый синтаксический анализатор для всех языков.Это отходит от почти универсального предположения, что синтаксические анализаторы интерпретируют грамматики конкретного языка. Но даже в рамках этого традиционного взгляда была признана привлекательность универсальных механизмов.
«Ключевым моментом, однако, является то, что поиск должен быть поиском универсалий, даже — и, возможно, особенно — в области обработки. Казалось бы, самая сильная теория синтаксического анализа — это та, которая утверждает, что интерпретатор грамматики сам по себе является универсальным механизмом, т.е. что существует один строго ограниченный интерпретатор грамматики, который является подходящей машиной для синтаксического анализа всех естественных языков »(Marcus, 1980, p.11).
Идея «синтаксический анализатор — это грамматика» имеет долгую историю; см. Phillips (1996, 2003), Kempson et al. (2001), а также статьи в Fodor and Fernandez (2015) о недавней перспективе. Фодор называет это представлением только грамматики производительности (PGO).
«Теория общественного мнения вступает в игру с одним мощным преимуществом: должны быть психологические механизмы для разговора и понимания, и соображения простоты, таким образом, возлагают бремя доказательства на любого, кто будет утверждать, что существует нечто большее» (Fodor, 1978, стр.470).
Однако, допуская, что это влечет за собой более простую теорию, Фодор отвергает эту идею, не находя мотивации для движения вне автономной грамматики ( там же, ., 472). Это предполагает, что движение принципиально сложно для синтаксического анализа механизмов (которые должны предпочесть фразово-структурные механизмы трансформационным). Однако в ULTRA смещение не является сложностью по сравнению с более простыми механизмами; смещение — это основной механизм.
Смещение не является уникальной особенностью человеческого языка
Часто говорят, что смещение присуще только человеческому языку, и искусственные коды избегают этого свойства.Но смещение появляется в языках программирования в том же смысле, что и в ULTRA. Простой пример иллюстрирует: порядок, в котором пользователи нажимают клавиши на калькуляторе, не является порядком, в котором выполняются соответствующие вычисления. На практике калькуляторы компилируют входные данные в обратную польскую нотацию для машинного использования с помощью алгоритма маневровой верфи Дейкстры (SYA).
Пример не праздный; алгоритм сортировки стека (4) по существу идентичен SYA. Лексические заголовки (существительные и глаголы) «перенаправляются» непосредственно на интерпретацию, как числовые константы в калькуляторе.Между тем спутники, образующие их расширенные проекции, сортируются в соответствии с их относительным рангом, как и арифметические операторы. По этой аналогии картографический порядок соответствует порядку приоритета арифметических операторов.
На самом деле, хотя это свойство мало используется, SYA является протоколом сортировки; многие заказы на ввод приводят к одному и тому же внутреннему расчету. Как пользователи калькуляторов, мы используем одну схему ввода (инфиксную нотацию), но подойдут и другие. Стандартизированный порядок ввода для калькуляторов имеет тот же статус, что и отдельные языки по отношению к ULTRA: пользователи могут придерживаться узких привычек упорядочивания, но алгоритм автоматически обрабатывает многие другие заказы.
Грамматичность и грамматичность
Одна из центральных задач, приписываемых грамматикам, — отличать грамматические предложения языка от неграмматических строк. В ULTRA знание грамматики сильно отличается от знания грамматичности и . Первый вид знания в основном касается компьютерных интерпретаций. Но инвариантный процесс, интерпретирующий поверхностный порядок одного языка, может одинаково интерпретировать порядки других языков. С этой точки зрения существует только один I-язык и единственная грамматика производительности, которая его обеспечивает.Хотя этот вывод является привлекательным, остается важный вопрос: откуда берутся отдельные языки с явно различающейся грамматикой?
Возможные расширения более полной теории синтаксиса
В этом разделе рассматриваются два типа проблем, возникающих при интерпретации стековой сортировки как устройства производительности. Первый касается согласования теории с тем, что известно о языковой обработке в реальном времени; второй касается расширения модели до свойств синтаксиса, которые остаются необъясненными.Даже подробное обсуждение этих проблем, не говоря уже об оправдании каких-либо решений, выходит за рамки данной статьи. Цель состоит в том, чтобы просто набросать проблемы и указать направления для дальнейшей работы.
Реакция против предсказания: инкрементность и жесткий порядок слов
Что касается обработки, то одна проблема состоит в том, что этому подходу, кажется, противоречат убедительные доказательства пословной постепенности в понимании (особенно в парадигме визуального мира; см. Tanenhaus and Trueswell, 2006).ULTRA является «пешеходом» в том смысле, против которого предостерегает Стейблер (1991). В каждом домене интерпретация «снизу вверх» не может начаться, пока не будет обнаружен лексический корень fseq.
Одна из возможностей согласования ULTRA с инкрементальностью основана на различии между реактивными процессами, такими как процедура сортировки стека и прогнозная обработка (см. Braver et al., 2007; Huettig and Mani, 2016). Идея состоит в том, что сортировка стека является реактивным механизмом языкового восприятия; это контрастирует — и обязательно дополняется — возможностями прогнозирования, связанными с нисходящей обработкой и производством.Только последняя система содержит выученные языковые грамматические знания. Это предложение перекликается с другими подходами с двухэтапным процессом синтаксического анализа, такими как Sausage Machine Фрейзера и Фодора (1978). ULTRA похож на их предварительный упаковщик фраз (PPP), быстрый низкоуровневый конструктор структур, отличающийся от крупномасштабного решения проблем, выполняемого их диспетчером структуры предложений (SSS). Маркус выражает аналогичную точку зрения, описывая синтаксический анализатор как «быстрый,« глупый »черный ящик» (Marcus, 1980: 204), производящий частичный анализ, дополненный интеллектуальным решением проблем для построения крупномасштабной структуры.
Я полагаю, что свидетельства постепенного увеличения количества слов за слово могут быть согласованы с существующей теорией посредством взаимодействия между реакцией и предсказанием, используя понятие «гиперактивность» (Momma et al., 2015). Идея состоит в том, что понимание может пропустить вперед, создавая видимость инкрементности, если лексический корень (существительное или глагол) предоставляется заранее путем предсказания. Что-то вроде этого кажется правдой.
«Появляется все больше свидетельств того, что постигающие часто выстраивают структурные позиции в своих анализах до того, как столкнутся со словами во входных данных, которые фонологически реализуют эти позиции […] Возьмем только один пример, в таком языке, который является окончательным, например, японском, может быть необходимо система построения структуры для создания позиции для заголовка фразы до того, как она завершит аргументы и дополнения, предшествующие заголовку »(Phillips and Lewis, 2013, p.19).
Дополнительная система прогнозирования может помочь решить еще две проблемы для ULTRA: объяснить, как возможно производство, и почему существуют разные языки с различным, относительно жестким порядком слов. Алгоритм сортировки стека — это однонаправленный синтаксический анализатор; не существует тривиального способа «повернуть поток вспять» для производства. Столкнувшись с этой неопределенностью, было бы естественно полагаться на предсказание, чтобы обеспечить порядок слов в производстве. Чтобы упростить производство, полезно, чтобы порядок слов был предсказуемым; в свою очередь, с помощью этой системы можно изучить тенденции порядка слов в языковой среде.Это предполагает наличие петли обратной связи и вероятного пути возникновения и расхождения относительно жестких порядков слов.
Первенство против новизны и двойственность семантики
Ряд важных синтаксических свойств остается невыясненным. Чтобы распространить предложение на отдаленно адекватную теорию, эти свойства должны быть как-то рассмотрены. К ним относятся, во-первых, группа синтаксических свойств, относящихся к синтаксису A-bar, и так называемая двойственность семантики. Я предполагаю, что этот особый вид синтаксиса связан с важным различием в краткосрочной памяти между первичностью и новизной, опираясь на модель начала-конца (SEM) Хенсона (1998).В модели Хенсона первенство и новизна — разные эффекты, отражающие кодирование с адресацией по содержанию двух аспектов последовательной позиции.
Время давности естественно связано с памятью стека (последним вошел, первым ушел). С другой стороны, первенство естественным образом описывается памятью очереди (первым пришел — первым ушел). Помимо оптимального порядка доступа, существует еще одно важное различие между эффектами первенства и новизны. Проще говоря, первый элемент в последовательности остается первым элементом независимо от того, сколько элементов следует за ним; Сигнатура первичности данного элемента относительно стабильна во временной шкале, соответствующей синтаксическому анализу.Новизна отличается: каждый элемент в последовательности — это новый правый край, подавляющий доступность памяти на основе недавнего времени всего, что ему предшествует. Таким образом, мы ожидаем своего рода давления «используй или потеряй» в недавней памяти, но не в первичной памяти.
Предварительно я хотел бы предположить, что различные коды памяти первичности и недавности лежат в основе двойственности семантики и разделения между A-bar и A-синтаксисом. Своевременность, связанная со стеком, является основой для информационной нейтральной локальной перестановки, обычно характеризующейся вложенными зависимостями.Предположение, что первенство играет решающую роль в ненейтральном синтаксисе, напоминающем A-bar, предполагает объяснение группы удивительных свойств. Наиболее очевидна ассоциация дискурсивно-информационных эффектов с «левой периферией»: левый край доменов — это то место, где мы ожидаем, что первичная память будет играть значительную роль. Вовлечение первичной памяти также предполагает анализ эффектов превосходства в множественных конструкциях белых движений. В теориях, основанных на слияниях, такие конструкции (демонстрирующие перекрестные зависимости) проблематичны и требуют условных приспособлений, таких как Richards (1997) «Подкладывание» выводов.Думая об эффектах, связанных с первичной памятью, можно предположить более простое объяснение: упорядочивание нескольких WH-фраз — это вопрос доступа «первым пришел — первым ушел» (память очереди). Последнее свойство этой альтернативной синтаксической системы, которое можно рационализировать, — это перемещение на большие расстояния. Возможно, доступность перемещения на дальние расстояния для отношений A-bar является результатом стабильности первичной памяти, что делает элементы, встречающиеся на левой периферии, доступными для последующего вызова без особого труда, в отличие от недавней памяти (которая может поддерживать только короткие, локальные отзывать).Хотя это наводит на размышления, обращение к обширной литературе по синтаксису A-bar следует оставить на будущее.
А как насчет рекурсии?
Последняя проблема, вырисовывающаяся на заднем плане, — это рекурсия. ULTRA работает в синтаксических доменах, характеризуемых одним fseq. Это требует некоторого комментария, поскольку рекурсия является фундаментальным свойством синтаксиса. Для рекурсии также могут иметь решающее значение свойства памяти и вмешательство дополнительной системы прогнозирования. Интересно, что эпизодическая память человека, по-видимому, имеет независимую иерархическую структуру, возможно, в отличие от родственных животных (Tulving, 1999; Corballis, 2009).В модели SEM эпизодические маркеры создаются для групп внутри сгруппированных последовательностей (Henson, 1998). Лингвистическая рекурсия требует некоторого дополнительного механизма для обработки токена группы, соответствующего одной последовательности, как токена элемента в другой последовательности.
Как обсуждалось в разделе «Сравнение с существующими учетными записями Universal 20» в ULTRA, структурная неоднозначность не возникает без двусмысленности смысла внутри отдельных доменов. Однако структурная неоднозначность неизбежно возникает, когда присутствуют несколько доменов, с точки зрения того, какой домен встраивается в другой или где прикрепить элемент, который мог бы занимать позиции в двух разных доменах.Вот где «быстрый, глупый черный ящик» беспомощен и должен обращаться к другим ресурсам. Одним из очевидных источников помощи в объединении нескольких доменов является отдельная система прогнозирования с доступом к нисходящим сведениям о правдоподобных значениях контекста. Постоянная проблема разрешения неоднозначности встраивания также дает мотивацию к жесткому порядку слов, что резко снижает возможности прикрепления.
Важным моментом является то, что скобки определены относительно конкретного fseq.Рекурсивное встраивание одного домена в другой (например, номинал в качестве аргумента глагола) включает в себя проекцию скобки, соответствующей всей вложенной фразе, в пределах области встраивания. Рассмотрим следующий пример.
(11) Собака гналась за мячом.
Здесь есть три области сортировки: две номинальные проекции, встроенные в третью, вербальную проекцию (не считая возможности, что предложения содержат две области, фазы vP и CP). Их УЛЬТРА-брекетинг показан ниже.
(12) NP1 = [ [ собака ] ]
NP2 = [ a [ шаровой шар ] a ]
VP = [ NP1 [ чеканка ] [ NP2 NP2 ] NP1 ]
Этот пример иллюстрирует неоднозначность, которая сопровождает внедрение. Проблема в том, как связать именные фразы с позициями в глаголе fseq (то есть с тета-ролями). Поскольку тета-роли не выражены открыто (регистр — ненадежный ориентир), реактивный синтаксический анализатор должен использовать внешние средства (например, специфические для языка привычки упорядочивания или предсказания правдоподобных интерпретаций).
Последний пункт о рекурсии возвращается к вопросу о том, как работают калькуляторы, с помощью алгоритма маневрового двора Дейкстры. Такие вычисления рекурсивны. Но рекурсия не обрабатывается алгоритмом синтаксического анализа; скорее, он возникает на уровне интерпретации, когда частичные результаты арифметических операций используются в дальнейших вычислениях. Аналогичный вывод (рекурсия является семантической, а не синтаксической) возможен в рамках настоящей структуры, учитывая сходство между ULTRA и SYA. Примечательно, что обе процедуры компилируют ввод в Reverse Polish Notation, так называемый язык конкатенативного программирования, однозначно выражающий рекурсивные иерархические операции в последовательном формате.
Нужен ли вообще алгоритм?
Я показал, как особенно простой алгоритм улавливает ряд синтаксических явлений. Но вопрос в том, почему этот алгоритм ? В принципе возможны другие процедуры сортировки, которые могут привести к другим профилям предотвращения перестановок. Как мы можем оправдать выбор стековой сортировки в качестве правильной процедуры для синтаксического сопоставления?
Есть три важных ингредиента. Первый — это ориентация системы на анализатор, сопоставляющий звук со смыслом.Это не является логически необходимым; это просто один из разумных вариантов. Второй фактор — это линейность звука и смысла. Это просто для звуковых последовательностей, но гораздо меньше для интерпретаций, где это просто смелая гипотеза. Третий ингредиент — это выбор стековой памяти. Это может быть правдоподобно связано с эффектом модальности: внятный речевой ввод порождает необычно сильные эффекты новизны (Surprenant et al., 1993). Кажется небольшим скачком предположить, что формальный стек, используемый в алгоритме, может просто (и грубо) отражать преобладание эффектов новизны в памяти для лингвистического материала.
До сих пор сортировка стека была реализована с использованием явного алгоритма. Это может быть ненужным. Вместо того, чтобы думать о сортировке стека как о наборе явных инструкций, мы могли бы переосмыслить ее как антиконфликтное предубеждение между доступностью элементов в памяти с точки зрения эффектов давности и извлечением для жесткой последовательности интерпретации. Если это на правильном пути, возможно, что не пришлось развиваться новому когнитивному механизму, чтобы объяснить эти эффекты. Остается понять, откуда берется само упорядочение интерпретаций (fseq) — вопрос, на котором я не буду здесь рассуждать.
Заключение
Подводя итог, простой алгоритм (4) отображает 213-избегающие порядки слов в восходящую композиционную последовательность, отображая 213-содержащие порядки в девиантные последовательности. Хотя входные и выходные данные сопоставления представляют собой последовательности, присутствует иерархическая структура: алгоритмические шаги реализуют левую и правую скобки, почти точно там, где их помещают стандартные учетные записи. Учетная запись отличается от стандартных учетных записей тем, что для всех заказов назначена однозначная брекетинг.
Эта модель улучшает существующие учетные записи ограничений порядка слов, которые требуют дополнительных условий (например,g., ограничения на движение вместе с принципами линеаризации), помимо построения основной синтаксической структуры. В ULTRA эти эффекты выпадают из единого процесса в реальном времени. В свою очередь, синтаксическое смещение, долгое время считавшееся любопытным усложнением, становится фундаментальным грамматическим механизмом. Не требуется изучение специфических свойств языка; одна грамматика интерпретирует множество порядков.
Должно быть ясно, что описанная здесь система является лишь частью синтаксического познания. Эта система строит одну расширенную проекцию за раз; необходимы дополнительные механизмы для встраивания одного домена в другой.Однако это может быть достоинством: есть соблазн определить области работы для этой архитектуры с помощью фаз, которые, таким образом, являются особенными по принципиальным причинам.
Более того, сортировка стека обрабатывает только нейтральную информацию структуры. При этом игнорируется другой важный компонент синтаксиса, так называемая структура дискурса-информации, связанная с потенциально дальними зависимостями A-bar. Этот недостаток также может быть достоинством, предлагающим принципиальную основу двойственности семантики.Я предположил, что первичная память играет центральную роль в этих эффектах, потенциально объясняя несколько любопытных свойств (левизну, большое расстояние и пересечение).
Подняв наш взгляд, можно сделать больший вывод, что большая часть механизма синтаксического познания может сводиться к эффектам, не специфичным для языка. Излишне говорить, что это всего лишь программный набросок; будущие исследования определят, можно ли и каким образом объединить стековую сортировку ULTRA в более полную модель языка.
Авторские взносы
Автор подтверждает, что является единственным соавтором данной работы, и одобрил ее к публикации.
Заявление о конфликте интересов
Автор заявляет, что исследование проводилось при отсутствии каких-либо коммерческих или финансовых отношений, которые могут быть истолкованы как потенциальный конфликт интересов.
Благодарности
Части этой работы были впервые разработаны на семинаре для выпускников Университета Аризоны (2015) и представлены на Симпозиуме POL в Токио (2016), LCUGA 3 (2016) и Ежегодном собрании LSA (2017).Я благодарен публике на этих площадках и многочисленным коллегам за полезные обсуждения. Я хотел бы поблагодарить следующих: Клауса Абельса, Дэвида Аджера, Боба Бервика, Тома Бевер, Эндрю Карни, Ноама Хомского, Гульельмо Чинкве, Дженнифер Калбертсон, Сэндиуэй Фонг, Томаса Графа, Джона Хейла, Хайди Харли, Норберта Хорнштейна, Майкл Джарретт, Ричард Кейн, Хильда Купман, Диего Кривочен, Марко Кульман, Массимо Пиаттелли-Пальмарини, Колин Филлипс, Пол Пьетроски, Маркус Саерс, Йосуке Сато, Дэн Сиддики, Доминик Спортиш, Хуан Урьягерека, Элли ван Гелдерен и Стефан Гельдерен, Уилсон.Я особенно благодарен аспирантам, которые участвовали в моей исследовательской группе Stack-Sorting Research (2015-2016). Конечно, все ошибки и недоразумения в этой статье — мои собственные.
Сноски
Список литературы
Абельс, К., Нилман, А. (2012). Линейные асимметрии и LCA. Синтаксис 15, 25–74. DOI: 10.1111 / j.1467-9612.2011.00163.x
CrossRef Полный текст | Google Scholar
Барбирс, С., ван дер Аувера, Дж., Беннис, Х., Бёф, Э., де Фогелар, Г., и ван дер Хам, М. (2008). Синтаксический атлас голландских диалектов, Vol. II , Амстердам: Издательство Амстердамского университета.
Google Scholar
Бервик Р., Хомский Н. (2016). Почему только мы: язык и эволюция . Кембридж, Массачусетс: MIT Press.
Google Scholar
Бравер Т.С., Грей Дж. Р. и Берджесс Г. К. (2007). «Объяснение множества разновидностей вариаций рабочей памяти: двойные механизмы когнитивного контроля», в Variation in Working Memory , eds A.Конвей, К. Джарролд, М. Кейн, А. Мияке и Дж. Тоуз (Нью-Йорк, Нью-Йорк: издательство Оксфордского университета), 76–106.
Google Scholar
Чеси К. и Моро А. (2015). «Тонкая зависимость между компетенцией и эффективностью», в 50 лет спустя: размышления об аспектах Хомского , ред. Á. Дж. Галлего и Д. Отт (Кембридж, Массачусетс: Рабочие документы Массачусетского технологического института по лингвистике), 33–46.
Google Scholar
Хомский, Н. (1965). Аспекты теории синтаксиса .Кембридж, Массачусетс: MIT Press.
Google Scholar
Хомский, Н. (1995). Программа минимализма . Кембридж, Массачусетс: MIT Press.
Google Scholar
Чинкве, Г. (1999). Наречия и функциональные головы: кросс-лингвистическая перспектива . Оксфорд: Издательство Оксфордского университета.
Google Scholar
Чинкве, Г. (2005). Получение универсальных 20 Гринберга и их исключения. Linguistic Inquiry 36, 315–332. DOI: 10.1162/002438
96917CrossRef Полный текст | Google Scholar
Делл, Г. С., Чанг, Ф. (2014). P-цепь: связь производства предложений и их нарушений с пониманием и усвоением. Phil. Пер. R. Soc. В 369: 20120394. DOI: 10.1098 / rstb.2012.0394
PubMed Аннотация | CrossRef Полный текст | Google Scholar
Фодор, Дж. Д. (1978). Стратегии синтаксического анализа и ограничения на преобразования. Linguistic Inquiry 9, 427–473.
Google Scholar
Фодор, Дж. Д., Фернандес, Э. (2015). Спецвыпуск по грамматикам и синтаксическим анализаторам: к единой теории знания и использования языков. J. Психолингвист. Res. 44, 1–5. DOI: 10.1007 / s10936-014-9333-3
CrossRef Полный текст
Фрейзер Л. и Фодор Дж. Д. (1978). Колбасная машина: новая модель двухэтапного разбора. Познание 6, 291–325. DOI: 10.1016 / 0010-0277 (78)
-1
CrossRef Полный текст | Google Scholar
Гринберг, Дж.(1963). «Некоторые универсалии грамматики с особым упором на порядок значимых элементов», in Universals of Language , ed J. Greenberg (Cambridge, MA: MIT Press), 73–113.
Google Scholar
Хюттиг Ф. и Мани Н. (2016). Необходимо ли предсказание для понимания языка? Возможно нет. Lang. Cogn. Neurosci. 31, 19–31. DOI: 10.1080 / 23273798.2015.1072223
CrossRef Полный текст | Google Scholar
Джаясилан, К.А.(2008). Простая структура фразы и синтаксис без спецификатора. Биолингвистика 2, 87–106.
Google Scholar
Джоши А. К. (1990). Обработка скрещенных и вложенных зависимостей: автоматическая точка зрения на психолингвистические результаты. Lang. Cogn. Процесс 5, 1–27. DOI: 10.1080 / 0169096
02095
CrossRef Полный текст | Google Scholar
Кейн Р. (1994). Антисимметрия синтаксиса . Кембридж, Массачусетс: MIT Press.
Google Scholar
Кемпсон, Р., Мейер-Виол, В., и Габбей, Д. (2001). Динамический синтаксис . Оксфорд: Блэквелл.
Google Scholar
Кнут, Д. (1968). Искусство программирования, Vol. 1. Основные алгоритмы . (Ридинг, Массачусетс: Эддисон-Уэсли).
Купман, Х. (2000). Синтаксис спецификаторов и заголовков . Лондон: Рутледж.
Маркус, М. П. (1980). Теория синтаксического распознавания естественных языков . Кембридж, Массачусетс: MIT Press.
Google Scholar
Марр, Д.(1982). Видение: компьютерное исследование человеческого представления и обработки визуальной информации . Нью-Йорк, штат Нью-Йорк: В. Х. Фриман.
Мама С., Слевц Л. Р. и Филлипс К. (2015). «Время планирования глаголов в активных и пассивных предложениях», в плакате , представленном на 28-й ежегодной конференции CUNY по обработке человеческих приговоров (Лос-Анджелес, Калифорния).
Google Scholar
Филлипс К. и Льюис С. (2013). Порядок образования производных в синтаксисе: свидетельства и архитектурные последствия. Шпилька. Линг. 6, 11–47.
Google Scholar
Ричардс, Н. (1997). Что куда движется и когда на каком языке? Докторская диссертация, Массачусетский технологический институт.
Ричардс, Н. (2010). Прорезывающие деревья . Кембридж, Массачусетс: MIT Press.
Google Scholar
Рицци, Л. (1997). «Тонкая структура левой периферии», в Elements of Grammar: Handbook in Generative Syntax , ed L. Haegeman (Dordrecht: Kluwer), 281–337.
Google Scholar
Шмид Т. и Фогель Р. (2004). Диалектные вариации в немецких трехглагольных кластерах: поверхностно-ориентированное описание ОТ. J. Compar. Германский линг. 7, 235–274. DOI: 10.1023 / B: JCOM.0000016639.53619.94
CrossRef Полный текст
Шихан М., Биберауэр Т., Робертс И., Песецки Д. и Холмберг А. (2017). Последнее-за-окончательное условие: синтаксический универсал, Vol. 76 , Кембридж, Массачусетс: MIT Press.
Стейблер, Э.П. младший (1991). «Избегайте парадокса пешехода», в Principle-Based Parsing: Computing and Psycholinguistics , eds R. Berwick, S. Abney, and C. Tenny (Dordrecht: Kluwer), 199–237.
Google Scholar
Starke, M. (2004). «Об отсутствии спецификаторов и природе голов», в The Cartography of Syntactic Structures, Vol. 3: Структуры и за его пределами , под ред. А. Беллетти. (Нью-Йорк, Нью-Йорк: издательство Оксфордского университета), 252–268.
Стедди, С., и Самек-Лодович, В. (2011). О некграмматичности движения остатка в выводе универсального Гринберга 20. Linguistic Inquiry 42, 445–469. DOI: 10.1162 / LING_a_00053
CrossRef Полный текст | Google Scholar
Стидман М. (2000). Синтаксический процесс . Кембридж, Массачусетс: MIT Press.
Google Scholar
Таненхаус, М. К., Трюзуэлл, Дж. К. (2006). «Движение глаз и понимание устной речи», в Справочнике по психолингвистике , ред.Traxler и M. A. Gernsbacher (Нью-Йорк, Нью-Йорк: Elsevier Academic Press), 863–900.
Google Scholar
Тулвинг, Э. (1999). «Об уникальности эпизодической памяти», в Cognitive Neuroscience of Memory , ред. Л. Нильссон и Х. Дж. Маркович (Ашленд, Огайо: Хогрефе и Хубер), 11–42.
Google Scholar
Вурмбранд, С. (2006). «Группы глаголов, повышение и реструктуризация глаголов» в The Blackwell Companion to Syntax , Vol. V, редакторы М. Эверарт и Х.ван Римсдейк (Оксфорд: Блэквелл), 227–341.
Google Scholar
Zwart, C.J. (2007). Некоторые заметки о происхождении и распространении IPP-эффекта. Groninger Arbeiten zur Germanistischen Linguistik 45, 77–99.
Google Scholar
Комбинатор Разбор
Глава 31 Programming in Scala, First Edition
Combinator Parsing
Мартин Одерски, Лекс Спун и Билл Веннерс
10 декабря 2008 г.
Иногда может потребоваться обработка небольшого специального язык.Например, вам может потребоваться прочитать файлы конфигурации для вашего программного обеспечения, и вы хотите чтобы их было легче изменять вручную, чем XML. В качестве альтернативы, возможно вы хотите поддерживать язык ввода в своей программе, например поиск условия с логическими операторами (компьютер, найди мне фильм «с` пробелом кораблей и без «любовных историй»). Какова бы ни была причина, вы понадобится парсер . Вам нужен способ конвертировать ввод в некую структуру данных, которую может обрабатывать ваше программное обеспечение.
По сути, у вас есть только несколько вариантов.Один из вариантов — свернуть собственный парсер (и лексический анализатор). Если вы не эксперт, это жесткий. Если вы эксперт, это все равно займет много времени.
Альтернативный вариант — использовать генератор синтаксического анализатора. Существуют довольно много таких генераторов. Некоторые из наиболее известных — Yacc и Bison для парсеров, написанных на C и ANTLR для парсеров, написанных на Ява. Вам, вероятно, также понадобится генератор сканера, такой как Lex, Flex, или JFlex, чтобы пойти с Это. Это могло бы быть лучшим решением, за исключением пара неудобств.Вам необходимо изучить новые инструменты, в том числе их — иногда непонятные — сообщения об ошибках. Вам также необходимо выяснить как подключить вывод этих инструментов к вашей программе. Это может ограничить выбор языка программирования и усложнить инструментальная цепочка.
В этой главе представлена третья альтернатива. Вместо использования автономный предметно-ориентированный язык генератора парсеров, вы использовать внутренний язык домена или внутренний DSL для короткая. Внутренний DSL будет состоять из библиотеки парсера. комбинаторы — функции и операторы, определенные в Scala, которые будут служить строительными блоками для парсеров.Эти строительные блоки будут один в один сопоставлены с конструкциями контекстно-свободной грамматики, чтобы сделать их Легко понять.
В этой главе представлена только одна языковая функция, которой не было объяснялось ранее: это алиасинг в Раздел 31.6. Однако в этой главе широко используются несколько другие функции, которые были описаны в предыдущих главах. Среди прочего, параметризованные типы, абстрактные типы, функции как объекты, оператор перегрузка, параметры по имени и неявные преобразования все играют важные роли.В этой главе показано, как эти языковые элементы могут быть объединены в дизайне библиотеки очень высокого уровня.
Концепции, описанные в этой главе, имеют тенденцию быть более сложными. чем в предыдущих главах. Если вы хорошо разбираетесь в компиляторе конструкции, вы получите от нее пользу, прочитав эту главу, потому что она поможет вам лучше взглянуть на вещи. Однако единственный предварительным условием для понимания этой главы является то, что вы знаете о регулярные и контекстно-свободные грамматики. Если вы этого не сделаете, материал в этом главу также можно спокойно пропустить.
31.1 Пример: арифметические выражения [ссылка]
Начнем с примера. Скажем, вы хотите создать парсер для арифметические выражения, состоящие из чисел с плавающей запятой, круглых скобок и бинарные операторы +, -, * и /. Первый шаг всегда записывать грамматику для анализируемого языка. Вот грамматика для арифметические выражения:
expr | знак равно | термин \ {«+» термин | «-» срок\}. |
срок | знак равно | фактор \ {«*» фактор | «/» Коэффициент \}. |
фактор | знак равно | floatPointNumber | «(» Выражение «)». |
Здесь, | обозначает альтернативные производства, а \ {… \ hspace {-1,5 pt } \} обозначает повторение (ноль и более раз). И хотя в этом примере он не используется, […] обозначает необязательный вхождение.
Эта контекстно-свободная грамматика формально определяет язык арифметические выражения. Каждое выражение (представленное expr ) является термином , за которым может следовать последовательность операторов + или — и далее срок с. Член — это фактор , за которым может следовать последовательность операторов * или / и далее множитель с. Коэффициент равен числовой литерал или выражение в скобках. Обратите внимание, что грамматика уже кодирует относительный приоритет операторов.Для Например, * связывается сильнее, чем +, потому что * операция дает член , тогда как операция + дает expr и expr s могут содержать термин s, но термин может содержать expr , только если последнее заключено в круглые скобки.
Теперь, когда вы определили грамматику, что дальше? Если вы используете Scala комбинаторные парсеры, вы в основном закончили! Вам нужно только выполнить некоторые систематические замены текста и обернуть синтаксический анализатор в класс, как показано в листинге 31.1:
импортировать scala.util.parsing.combinator._
class Arith расширяет JavaTokenParsers { def expr: Parser [Any] = term ~ rep ("+" ~ term | "-" ~ term) def term: Parser [Any] = factor ~ rep ("*" ~ factor | "/" ~ factor) def-фактор: Parser [Any] = FloatingPointNumber | "(" ~ выражение ~ ")" }
Листинг 31.1. Анализатор арифметических выражений.
Парсеры для арифметических выражений содержатся в классе, который наследуется от черта JavaTokenParsers. Эта черта обеспечивает базовую технику для написания парсера, а также предоставляет некоторые примитивные парсеры, которые распознавать некоторые классы слов: идентификаторы, строковые литералы и числа.В примере из Листинга 31.1 вам нужен только примитив парсер floatPointNumber, унаследованный от этого черта характера.
Три определения в классе Arith представляют продукцию для арифметические выражения. Как видите, они очень внимательно следят за постановкой. контекстно-свободной грамматики. Фактически, вы могли бы сгенерировать эту часть автоматически из контекстно-свободной грамматики, выполнив ряд простая замена текста:
- Каждое производство становится методом, поэтому вам нужно добавить к нему префикс с деф.
- Тип результата каждого метода — Parser [Any], поэтому вам нужно чтобы изменить символ :: = на «: Parser [Any] =». Позже в этой главе вы узнаете, что означает тип Parser [Any], а также как сделать его более точным.
- В грамматике последовательная композиция была неявной, но в программе это выражается явным оператором: ~. Итак, вам нужно вставить ~ между каждые два последовательных символа продукции. В примере из Листинга 31.1 мы решили не напишите пробелы вокруг оператора ~.Таким образом, код парсера будет строго соответствовать внешний вид грамматики — он просто заменяет пробелы символами ~.
- Повторение выражается как rep (…) вместо \ {… \}. Аналогично (хотя и не показано в примере) option выражается opt (…) вместо […].
- Точка (.) В конце каждой продукции опускается — однако вы можете написать точка с запятой (;), если хотите.
Вот и все. Результирующий класс Arith определяет три parsers, expr, term и factor, которые могут использоваться для синтаксического анализа арифметических выражений и их частей.
31.2 Запуск парсера [ссылка]
Вы можете проверить свой синтаксический анализатор с помощью следующей небольшой программы:
объект ParseExpr расширяет Arith { def main (args: Array [String]) { println ("input:" + args (0)) println (parseAll (выражение, аргументы (0))) } }Объект ParseExpr определяет основной метод, который анализирует первый переданный ему аргумент командной строки. Он печатает исходный входной аргумент, а затем печатает свою проанализированную версию. Парсинг выполняется выражением:
parseAll (выражение, вход)Это выражение применяет синтаксический анализатор expr к заданному входу.Ожидается, что все входные совпадения, , то есть , отсутствуют символы, завершающие анализируемое выражение. Также есть метод parse, который позволяет вам анализировать входной префикс, оставляя остаток непрочитанный.
Вы можете запустить арифметический анализатор с помощью следующей команды:
$ Scala ParseExpr "2 * (3 + 7)" ввод: 2 * (3 + 7) [1.12] проанализировано: ((2 ~ List ((* ~ (((~ ((3 ~ List ()) ~ List ((+ ~ (7 ~ Список ()))))) ~))))) ~ Список ())Выходные данные говорят вам, что синтаксический анализатор успешно проанализировал входную строку. до позиции [1.12]. Это означает первая строка и двенадцатый столбец — другими словами, вся входная строка — были проанализированы. Игнорируем пока результат после «parsed:».
Здесь парсер expr разобрал все до окончательного закрытия скобка, которая не является частью арифметическое выражение.Затем метод parseAll выдал сообщение об ошибке, которое сказал, что он ожидал оператора — в момент закрытия скобка. Позже в этой главе вы узнаете, почему было выдано именно это сообщение об ошибке. и как его можно улучшить.
31.3 Базовые синтаксические анализаторы регулярных выражений [ссылка]
Синтаксический анализатор арифметических выражений использовал другой синтаксический анализатор с именем floatPointNumber. Этот парсер, унаследованный от Супертрайт Арита, JavaTokenParsers, распознает число с плавающей запятой в формат Java.Но что делать, если вам нужно разобрать числа в формат, который немного отличается от формата Java? В этой ситуации вы можете использовать регулярное выражение парсер .
Идея состоит в том, что вы можете использовать любое регулярное выражение в качестве парсер. Регулярное выражение анализирует все строки, которым оно может соответствовать. Его Результат — это проанализированная строка. Например, парсер регулярных выражений в листинге 31.2 описаны идентификаторы Java:
объект MyParsers расширяет RegexParsers { val identity: Parser [String] = "" "[a-zA-Z _] \ w *" "".р }
Листинг 31.2. Анализатор регулярных выражений для идентификаторов Java.
Объект MyParsers в листинге 31.2 наследуется от трейта RegexParsers, тогда как Ариф унаследовал от JavaTokenParsers. Разбор Scala комбинаторы организованы в иерархию признаков, которые все содержится в пакете scala.util.parsing.combinator. На высшем уровне trait — это Parsers, который определяет очень общую структуру синтаксического анализа. для всевозможных вводов. Уровень ниже — это трейт RegexParsers, который требует, чтобы ввод представлял собой последовательность символов и предусматривал парсинг регулярных выражений.Еще более специализированным является черта JavaTokenParsers, реализующий парсеры для базовых классов слов. (или токены), как они определены в Java.
31,4 Другой пример: JSON [ссылка]
JSON, обозначение объектов JavaScript, является популярный формат обмена данными. В этом разделе мы покажем вам, как написать парсер для него. Вот грамматика, описывающая синтаксис JSON:
значение | знак равно | obj | обр | stringLiteral | |
floatPointNumber | | ||
«ноль» | «правда» | «ложный». | ||
объект | знак равно | «{» [Участники] «}». |
обр | знак равно | «[» [значения] «]». |
члены | знак равно | член \ {«,» член \}. |
член | знак равно | stringLiteral «:» значение. |
значения | знак равно | значение \ {«,» значение \}. |
Значение JSON — это объект, массив, строка, число или единица. из трех зарезервированных слов null, true или false. Объект JSON — это (возможно, пустая) последовательность членов, разделенных запятыми. и заключены в фигурные скобки. Каждый член представляет собой пару строка / значение, в которой строка и значение разделяются двоеточием. Наконец, массив JSON — это последовательность значений, разделенных запятыми. и заключен в квадратные скобки. В качестве примера, Листинг 31.3 содержит адресную книгу в формате как объект JSON.
{ "адресная книга": { "name": "Джон Смит", "адрес": { "улица": "Маркет-стрит, 10", "город": "Сан-Франциско, Калифорния", «zip»: 94111 }, "телефонные номера": [ «408 338-4238», «408 111-6892» ] } }
Листинг 31.3 — Данные в формате JSON.
Анализировать такие данные просто при использовании комбинаторов синтаксического анализатора Scala. Полный синтаксический анализатор показан в листинге 31.4. Этот синтаксический анализатор следует той же структуре, что и синтаксический анализатор арифметических выражений. Это снова прямое отображение продукции грамматики JSON. В постановках используется один ярлык, который упрощает грамматика: комбинатор repsep анализирует (возможно, пустую) последовательность терминов, разделенных заданной строкой-разделителем. Например, в в примере из Листинга 31.4, repsep (member, «,») анализирует разделенные запятыми последовательность членских условий. В противном случае продукции в парсере точно соответствуют продуктам грамматики, как было случай для парсеров арифметических выражений.
импортировать scala.util.parsing.combinator._
class JSON расширяет JavaTokenParsers {
значение по умолчанию: Parser [Any] = obj | обр | stringLiteral | floatPointNumber | "ноль" | "правда" | "ложный"
def obj: Parser [Any] = "{" ~ repsep (member, ",") ~ "}"
def arr: Parser [Any] = "[" ~ repsep (value, ",") ~ "]"
def member: Parser [Any] = stringLiteral ~ ":" ~ значение }
Листинг 31.4 — Простой парсер JSON.
Чтобы опробовать парсеры JSON, мы немного изменим фреймворк, чтобы парсер работал с файлом, а не с командной строкой:
импортировать java.io.FileReader
объект ParseJSON расширяет JSON { def main (args: Array [String]) { val reader = новый FileReader (args (0)) println (parseAll (значение, читатель)) } }
Основной метод в этой программе сначала создает FileReader объект. Затем он анализирует символы, возвращенные этим читателем. в соответствии со значением грамматики JSON.Обратите внимание, что parseAll и parse существуют в перегруженных вариантах: оба могут принимать последовательность символов или, альтернативно, устройство чтения ввода в качестве второго аргумент.
Если вы сохраните объект «адресной книги», показанный в Листинге 31.3, в файл с именем address-book.json и запустите на нем программу ParseJSON, вы должны получить:
$ Scala ParseJSON address-book.json [13.4] проанализировано: (({~ List ((("адресная книга" ~:) ~ (({~ List ((( "имя" ~:) ~ "Джон Смит"), (("адрес" ~:) ~ (({~ Список ((( "street" ~:) ~ "10 Market Street"), (("city" ~:) ~ "Сан-Франциско , CA "), ((" zip "~:) ~ 94111))) ~})), ((" номера телефонов "~:) ~ (([~ Список ("408 338-4238", "408 111-6892")) ~])))) ~})))) ~})
31.5 Вывод парсера [ссылка]
Программа ParseJSON успешно проанализировала адресную книгу JSON. Однако вывод парсера выглядит странно. Вроде бы последовательность, состоящая из битов и частей ввода, склеенных вместе с списки и ~ комбинации. Этот вывод не очень полезный. Он менее читабелен для людей, чем ввод, но также слишком дезорганизован, чтобы его можно было легко проанализировать с помощью компьютера. Это время что-то с этим делать.
Чтобы понять, что делать, сначала нужно знать, что человек парсеры в фреймворках комбинатора возвращают результат (при условии, что они преуспеть в синтаксическом анализе ввода).Вот правила:
- Каждый синтаксический анализатор, записанный в виде строки (например: «{» или «:» или «null»), возвращает сама проанализированная строка.
- Синтаксические анализаторы регулярных выражений, такие как «» «[a-zA-Z _] \ w *» «». R также вернуть саму проанализированную строку. То же самое верно и для парсеры регулярных выражений, такие как stringLiteral или floatPointNumber, которые унаследованы от черты JavaTokenParsers.
- Последовательная композиция P ~ Q возвращает результаты как P, так и Q. результаты возвращаются в экземпляре класса case, который также записывается ~.Итак, если P возвращает «истина», а Q возвращает «?», То последовательная композиция P ~ Q возвращает ~ («true», «?»), Который печатается как (true ~?).
- Альтернативный состав P | Q возвращает результат либо P, либо Q, в зависимости от того, что удастся.
- Повторение rep (P) или repsep (P, разделитель) возвращает список результатов всех прогонов П.
- Параметр opt (P) возвращает экземпляр типа Option в Scala. Он возвращает Some (R), если P успешен с результатом R, и None, если P терпит неудачу.
- Объект JSON представлен в виде карты Scala типа Map [String, Any]. Каждый член представлен на карте как привязка ключ / значение.
- Массив JSON представлен в виде списка Scala типа List [Any].
- Строка JSON представлена как строка Scala.
{Case «{» ~ ms ~ «}» => Map () ++ ms} Помните, что оператор ~
в результате создает экземпляр класса case с тем же именем: ~. Вот определение этого класса — это
внутренний класс черт
Парсеры:
case class ~ [+ A, + B] (x: A, y: B) { переопределить def toString = "(" + x + "~" + y + ")" }
Имя класса намеренно совпадает с именем метод комбинатора последовательностей, ~. Таким образом, вы можете сопоставить результаты синтаксического анализатора с шаблонами, которые следуют той же структуре, что и сами парсеры.. В его обессахараемых версиях, где первым идет оператор ~, тот же шаблон читает ~ (~ («{«, Ms), «}»), но это гораздо менее разборчиво.Цель шаблона «{» ~ ms ~ «}» — убрать фигурные скобки, чтобы который вы можете получить в списке членов, полученном с помощью синтаксического анализатора repsep (member, «,»). В подобных случаях есть альтернатива, позволяющая избежать создание ненужных результатов парсера, которые немедленно отбрасываются совпадение с образцом. Альтернатива использует ~> и <~ парсер комбинаторы.(Карта () ++ _)
В листинге 31.5 показан полный анализатор JSON, который возвращает значимые результаты. Если вы запустите этот парсер в файле address-book.json, вы получите следующий результат (после добавления новых строк и отступов):
$ Scala JSON1Test address-book.json [14.1] проанализировано: Карта ( адресная книга -> Карта ( имя -> Джон Смит, адрес -> Карта ( улица -> 10 Маркет-стрит, город -> Сан-Франциско, Калифорния, zip -> 94111), номера телефонов -> Список (408 338-4238, 408111-6892) ) )
Это все, что вам нужно знать, чтобы приступить к написанию собственного парсеры.(x => ложь) ) }
Листинг 31.5. Полный синтаксический анализатор JSON, возвращающий значимые результаты.
Таблица 31.1 — Сводка комбинаторов синтаксического анализатора
«. f преобразование результатов Отключение вывода точки с запятой
Обратите внимание, что тело парсера значений в листинге 31.5 заключен в круглые скобки. Это немного трюк, чтобы отключить вывод точки с запятой в выражениях парсера. Вы видели в Разделе 4.2, что Scala предполагает наличие точка с запятой между любыми двумя строками, которые могут быть отдельными операторами синтаксически, если первая строка не заканчивается инфиксным оператором или две строки заключаются в круглые или квадратные скобки. Теперь ваша очередь мог бы написать | оператор в конце каждой альтернативы вместо начала следующего, например:
значение по умолчанию: Parser [Any] = obj | обр | stringLiteral | ...
В этом случае скобки вокруг тела синтаксического анализатора значений не потребовались бы. Однако некоторые люди предпочитают видеть | оператор в начале вторая альтернатива, а не в конце первой. Обычно это приводит к нежелательной точке с запятой между двумя строки, например:obj; | обр
Точка с запятой меняет структуру кода, приводя к сбою компиляции. Заключение всего выражения в круглые скобки избегает точки с запятой и обеспечивает правильную компиляцию кода., и | ты можешь написать такая грамматическая продукция без скобок.Кроме того, символические операторы занимают меньше визуальной площади, чем буквенные. Это важно для парсера, потому что он позволяет вам сконцентрируйтесь на грамматике, а не на комбинаторах сами себя. Чтобы увидеть разницу, представьте на мгновение, что была названа последовательная композиция (~), а затем была предложена альтернатива (|). называется orElse. Парсеры арифметических выражений в Листинг 31.1 здесь будет выглядеть следующим образом:
class ArithHypothetical расширяет JavaTokenParsers { def expr: Parser [Any] = term andThen rep (("+" andThen term) orElse ("-" и затем термин)) def term: Parser [Any] = factor andThen rep (("*" andThen factor) orElse ("/" И множитель)) def-фактор: Parser [Any] = floatPointNumber или Else ("(" AndThen expr andThen ")") }
Вы замечаете, что код становится намного длиннее, и его трудно «увидеть» грамматику среди всех этих операторов и скобок.С другой стороны, кто-то, кто плохо знаком с комбинаторным синтаксическим анализом, вероятно, мог бы лучше понять, что должен делать код.Выбор между символьными и буквенными именами
В качестве руководства по выбору между символическими и буквенными именами мы рекомендую следующее:
- Используйте символические имена в тех случаях, когда они уже имеют общепризнанное значение. Например, никто не стал бы рекомендуется писать add вместо + для числового сложения.
- В противном случае отдайте предпочтение буквенным именам, если вы хотите, чтобы ваш код быть понятным для случайных читателей.
- Вы по-прежнему можете выбирать символические имена для доменных библиотек, если это дает явные преимущества в удобочитаемости, и вы не ожидаете в любом случае, случайный читатель без твердого опыта в данной области сможет сразу понять код.
31.6 Реализация синтаксических анализаторов комбинаторов [ссылка]
В предыдущих разделах было показано, что синтаксические анализаторы комбинаторов Scala предоставить удобные средства для создания собственных синтаксических анализаторов. С они не более чем библиотека Scala, они легко вписываются в ваши программы Scala. Так что очень легко совместить парсер с некоторыми код, обрабатывающий полученные результаты, или для подгонки парсера так что он принимает входные данные из определенного источника (скажем, файла, строка или массив символов).
Как это достигается? В оставшейся части этой главы вы посмотрите «под капотом» библиотеки синтаксического анализатора комбинатора. Вы увидите, что за парсер, и как примитивные парсеры и комбинаторы парсеров встреченные в предыдущих разделах, реализованы. Можно смело пропустить эти части, если все, что вы хотите сделать, это написать несколько простых синтаксических анализаторов комбинаторов. С другой стороны, прочтение оставшейся части этой главы должно дать вам более глубокое понимание комбинаторных синтаксических анализаторов, в частности, и принципы проектирования комбинаторного предметно-ориентированного языка в целом.
Ядро структуры синтаксического анализа комбинаторов Scala содержится в черта характера scala.util.parsing.combinator.Parsers. Эта черта определяет тип Parser, а также все основные комбинаторы. Кроме если прямо указано иное, определения, приведенные в все следующие два подраздела относятся к этой характеристике. То есть предполагается, что они содержится в определении признака, которое начинается следующим образом:
пакет scala.util.parsing.combinator trait Parsers { ... }
По сути, парсер — это просто функция от некоторого типа ввода. к результату синтаксического анализа. В первом приближении тип можно было бы записать следующим образом:введите Parser [T] = Input => ParseResult [T]
Вход парсера
Иногда синтаксический анализатор читает поток токенов вместо необработанной последовательности символы. Затем используется отдельный лексический анализатор для преобразования потока. сырых символов в поток токенов. Тип входных данных парсера определяется следующим образом:
тип Input = Reader [Elem]
Класс Reader идет из пакета Scala.util.parsing.input. Он похож на Stream, но также отслеживает позиции всех считываемых элементов. Тип Elem представляет собой индивидуальный ввод элементы. Это абстрактный тип член трейта Parsers:тип Elem
Это означает, что подклассы и субтитры Парсерам необходимо создать экземпляр класса Elem для типа ввода. элементы, которые анализируются. Например, RegexParsers и JavaTokenParsers исправляет Elem, чтобы он был равен Char. Но это было бы также можно установить для Elem какой-либо другой тип, например тип токенов, возвращенных из отдельного лексера.Результаты парсера
Синтаксический анализатор может либо успешно, либо выйти из строя на некотором заданном входе. Следовательно, класс ParseResult имеет два подкласса для представления успеха и отказ:
запечатанный абстрактный класс ParseResult [+ T] case class Success [T] (результат: T, in: Input) расширяет ParseResult [T] case class Failure (msg: String, in: Input) расширяет ParseResult [ничего]
Вариант Success переносит результат, возвращенный парсером, в его параметр результата. Тип результатов парсера произвольный; это почему ParseResult, Success и Parser параметризованы с параметром типа T.Параметр типа представляет типы результатов возвращается данным парсером. Успех также принимает второй параметр, in, который относится к вводу, который следует сразу за частью, парсер поглотил. Это поле необходимо для объединения парсеров, поэтому что один парсер может работать за другим. Обратите внимание, что это чисто функциональный подход к парсингу. Ввод не читается как сторона эффект, но он сохраняется в потоке. Парсер анализирует некоторую часть входной поток, а затем возвращает оставшуюся часть в своем результате.Другой подкласс ParseResult — Отказ. Этот класс занимает в качестве параметра сообщение, описывающее причину сбоя парсера. Нравиться Успех, Неудача также принимает оставшийся входной поток как второй параметр. Это нужно не для цепочки (парсер не продолжить после сбоя), но разместить сообщение об ошибке в правильное место во входном потоке.
Обратите внимание, что результаты синтаксического анализа определены как ковариантные в типе параметр T. То есть синтаксический анализатор, возвращающий строки как результат, скажем, совместим с парсером, возвращающим AnyRefs.
Класс Parser
Предыдущая характеристика парсеров как функций из вводы для анализа результатов были немного упрощены. Предыдущие примеры показали, что парсеры также реализуют такие методы, как ~ for последовательная композиция двух парсеров и | за их альтернативу состав. Итак, Parser на самом деле является классом, унаследованным от тип функции Input => ParseResult [T] и дополнительно определяет следующие методы:
абстрактный класс Parser [+ T] расширяется (Input => ParseResult [T]) {P => def apply (in: Input): ParseResult [T]
Поскольку синтаксические анализаторы являются функциями (, т.е. , наследуются от), им необходимо определить применить метод. Вы видите абстрактный метод применения в классе Parser, но это только для документации, так как тот же метод в любом случае унаследованный от родительского типа Input => ParseResult [T] (напомним, что этот тип является аббревиатурой от scala.Function1 [Вход, ParseResult [T]]). Метод apply еще не реализован в отдельных парсерах, унаследованных от абстрактного класса Parser.Эти парсеры будет обсуждаться после следующего раздела об этом псевдониме.
деф ~... def | ... ... }Наложение этого
Тело класса Parser начинается с любопытного выражения:
абстрактный класс Parser [+ T] расширяет ... {p =>
Предложение, такое как «id =>», сразу после открывающей фигурной скобки шаблон класса определяет идентификатор идентификатора как псевдоним для этого в класс. Как будто вы написали:val id = это
в теле класса, за исключением того, что компилятор Scala знает, что идентификатор псевдоним для этого.Например, вы можете получить доступ к объектно-частный член класса m, использующий id.m или this.m; эти два полностью эквивалентны. Первое выражение не будет компилироваться, если id были просто определены как val с его правой рукой стороне, потому что в этом случае компилятор Scala будет рассматривать id как нормальный идентификатор.Вы видели подобный синтаксис в Разделе 27.4, где он использовался, чтобы присвоить свой тип признаку. Псевдоним также может быть хорошим сокращением, когда вам нужно получить доступ к это внешнего класса.Вот пример:
class Outer {outer => class Inner { println (Внешний. этот эквалайзер) } }
В примере определяются два вложенных класса: Внешний и Внутренний. Внутри Внутреннее значение this внешнего класса упоминается дважды, используя разные выражения. Первое выражение показывает способ Java выполнения действий: перед зарезервированным словом this можно поставить префикс имя внешнего класса и точка; такое выражение тогда относится к this внешнего класса. Второе выражение показывает альтернатива, которую предоставляет вам Scala.Введя псевдоним с именем external для этого в классе Outer, вы можете ссылаться на этот псевдоним непосредственно также во внутренних классах. Способ Scala более краток и может также улучшится ясность, если вы правильно выберете имя псевдонима. Вы увидите примеры здесь и здесь.Парсеры одного токена
Class Parsers определяет общий элемент синтаксического анализатора, который может использоваться для проанализировать любой отдельный токен:
def elem (вид: String, p: Elem => Boolean) = новый парсер [Elem] { def применить (in: Input) = если (p (дюйм.первый)) Успех (in.first, in.rest) else Failure (вид + "ожидаемый", in) }
Этот парсер принимает два параметра: строку вида, описывающую, какой тип токена должен быть проанализирован и предикат p для Elems, который указывает, элемент соответствует классу анализируемых токенов.При применении синтаксического анализатора elem (kind, p) к некоторому входу Первый элемент входного потока проверяется с помощью предиката p. Если p возвращает истину, синтаксический анализатор завершает работу. Его результатом является элемент сам, а его оставшийся вход — это входной поток, начинающийся только после анализируемого элемента.С другой стороны, если p возвращает false, синтаксический анализатор выдает сообщение об ошибке, указывающее, что своего рода токен ожидался.
Последовательная композиция
Парсер elem использует только один элемент. Разбирать более интересных фраз, вы можете связать парсеры вместе с оператор последовательной композиции ~. Как вы видели раньше, P ~ Q — это синтаксический анализатор, который сначала применяет синтаксический анализатор P к заданной входной строке. Затем, если P удастся, синтаксический анализатор Q применяется ко входу это остается после того, как P выполнил свою работу.
Комбинатор ~ реализован как метод в классе Парсер. Его определение показано в Листинге 31.6. Метод является членом парсера. класс. Внутри этого класса p определяется частью «p =>» как псевдоним этого, поэтому p обозначает левый операнд (или: приемник) из ~. Его правый операнд представлен параметром q. Теперь, если p ~ q запускается на некотором вводе, сначала запускается p включен, и результат анализируется в соответствии с шаблоном. Если p успешно, q запускается на оставшемся входе in1. Если q также успешно, синтаксический анализатор в целом успешно.Его результатом является объект ~ содержащий как результат p (, т.е. , x), так и результат q (, то есть , y). С другой стороны, если либо p, либо q терпят неудачу, результат p ~ q — это объект Failure, возвращаемый функцией p или q.
абстрактный класс Parser [+ T] ... {p => ... def ~ [U] (q: => Parser [U]) = new Parser [T ~ U] { def apply (in: Input) = p (in) match { case Success (x, in1) => q (in1) match { case Success (y, in2) => Success (new ~ (x, y), in2) случай сбой => сбой } случай сбой => сбой } }
Листинг 31.6 — Метод комбинатора ~.
Тип результата ~ — это синтаксический анализатор, который возвращает экземпляр case class ~ с элементами типов T и U. выражение типа T ~ U — это просто более удобное сокращение для параметризованный тип ~ [T, U]. Как правило, Scala всегда интерпретирует операция двоичного типа, такая как A op B, как параметризованный тип op [A, B]. Это аналогично ситуации для паттернов, где двоичный шаблон P op Q также интерпретируется как приложение, , то есть , op (P, Q).{Case x ~ y => y}
Альтернативный состав
Альтернативный состав P | Q применяет либо P, либо Q к данный ввод. Сначала он пробует P. Если P успешно, весь синтаксический анализатор преуспевает с результатом P. В противном случае, если P не удается, то Q проверяется на том же входе, что и P. Результат Q тогда результат всего парсера.
Вот определение | как метод класса Parser:
def | (q: => Parser [T]) = новый Parser [T] { def apply (in: Input) = p (in) match { case s1 @ Success (_, _) => s1 случай отказа => q (дюйм) } }
Обратите внимание, что если P и Q не работают, то сообщение об ошибке определяется Q.Этот тонкий выбор обсуждается позже, в Раздел 31.9.Работа с рекурсией
Обратите внимание, что параметр q в методах ~ и | поименно — его типу предшествует =>. Этот означает, что фактический аргумент парсера будет оцениваться только тогда, когда q требуется, что должно быть только после выполнения p. Это позволяет писать рекурсивные парсеры, подобные следующим тот, который анализирует число, заключенное в произвольное количество круглых скобок:
def parens = FloatingPointNumber | "(" ~ parens ~ ")"
Если | и ~ взял параметров по значению , это определение будет немедленно вызвать переполнение стека, ничего не читая, потому что значение parens находится в середине его правой части.[U] (f: T => U): Parser [U] = new Parser [U] { def apply (in: Input) = p (in) match { case Success (x, in1) => Success (f (x), in1) случай сбой => сбой } } }Синтаксические анализаторы, которые не читают ввод
Также есть два парсера, которые не потребляют никаких входных данных: успешный и неудачный. В parser success (result) всегда успешно с заданным результатом. Ошибка синтаксического анализатора (msg) всегда завершается ошибкой с сообщением об ошибке msg. Оба реализованы как методы в парсерах трейтов, внешний трейт, который также содержит класс Parser:
def success [T] (v: T) = new Parser [T] { def apply (in: Input) = Успех (v, in) } def failure (msg: String) = new Parser [Nothing] { def apply (in: Input) = Failure (msg, in) }
Вариант и повтор
В синтаксических анализаторах свойств также определены комбинаторы опций и повторений. opt, rep и repsep.{Case r ~ rs => r :: rs} | успех (Список ()) )
}31.7 Строковые литералы и регулярные выражения [ссылка]
Парсеры, которые вы видели до сих пор использовал строковые литералы и регулярные выражения для разбора отдельных слов. Поддержка этих происходит от RegexParsers, подтипа Парсеры:
trait RegexParsers extends Parsers {
Этот трейт более специализирован, чем парсеры трейтов, в том смысле, что он работает только для входов, представляющих собой последовательности символов:тип Elem = Char
Он определяет два метода, литерал и регулярное выражение, со следующими сигнатурами:неявный литерал def (s: String): Parser [String] =... неявное def regex (r: Regex): Parser [String] = ...
Обратите внимание, что оба метода имеют неявный модификатор, поэтому они применяются автоматически. всякий раз, когда задана строка или регулярное выражение, но синтаксический анализатор ожидал. Это почему вы можете писать строковые литералы и регулярные выражения прямо в грамматике, без необходимости оборачивать их одним из этих методов. Например, парсер «(» ~ expr ~ «)» будет автоматически расширен до литерал («(«) ~ выражение ~ литерал («)»).Трейт RegexParsers также обрабатывает пробелы. между символами.Для этого он вызывает метод с именем handleWhiteSpace перед запуском синтаксического анализатора литерала или регулярного выражения. Метод handleWhiteSpace пропускает самую длинную входную последовательность, соответствующую whiteSpace. регулярное выражение, которое по умолчанию определено следующим образом:
защищенный val whiteSpace = "" "\ s +" "". r }
Если вы предпочитаете другую обработку белого пространства, вы можете переопределить whiteSpace val. Например, если вы хотите, чтобы пробелы вообще не пропускались, вы можете переопределить whiteSpace пустым регулярным выражением:объект MyParsers расширяет RegexParsers { переопределить val whiteSpace = "".р ... }
31.8 Лексирование и синтаксический анализ [ссылка]
Задача синтаксического анализа часто разделяется на две фазы. В фаза лексера распознает отдельные слова во входных данных и классифицирует их в некоторые классы токенов. Эта фаза также называется лексический анализ. Далее следует синтаксический анализ. фаза, анализирующая последовательности токенов. Синтаксический анализ также иногда просто называется синтаксическим анализом, хотя это немного неточно, лексический анализ также можно рассматривать как проблему синтаксического анализа.
Свойство Parsers, описанное в предыдущем разделе, можно использовать для любой фазы, потому что его входные элементы имеют абстрактный тип Elem. Для лексический анализ, Elem будет создан для Char, означающий отдельные символы, которые составить слово разбираются. Синтаксический анализатор, в свою очередь, создаст экземпляр Elem к типу токена, возвращаемому лексером.
Комбинаторы синтаксического анализаScala предоставляют несколько служебных классов для лексических и синтаксический анализ. Они содержатся в двух подпакетах, по одному для каждого вида анализа:
Scala.util.parsing.combinator.lexical scala.util.parsing.combinator.syntactical
Если вы хотите разделить парсер на отдельный лексер и синтаксический analyzer, вам следует обратиться к документации Scaladoc для этих пакетов. Но для простых синтаксических анализаторов обычно достаточно подхода на основе регулярных выражений, показанного ранее в этой главе.31.9 Сообщение об ошибке [ссылка]
Есть еще одна последняя тема, которая еще не была затронута: как парсер выдать сообщение об ошибке? Отчеты об ошибках для парсеров — это своего рода черное искусство.Одна из проблем заключается в том, что, когда парсер отклоняет какой-либо ввод, он вообще сталкивался с множеством разных неудач. Каждый альтернативный синтаксический анализ должен был потерпеть неудачу, причем рекурсивно в каждой точке выбора Который из обычно многочисленных сбоев следует отправлять в виде сообщений об ошибках Пользователь?
Библиотека синтаксического анализаScala реализует простую эвристику: среди всех отказов, тот, который произошел в последней позиции на входе, является выбрал. Другими словами, парсер выбирает самый длинный префикс, который все еще действителен и выдает сообщение об ошибке, в котором объясняется, почему анализ префикса не мог быть продолжен.Если есть несколько точек отказа в этой последней позиции, та, которая была выбирается последний посещенный.
Например, рассмотрите возможность запуска парсера JSON на ошибочном адресе. книга, которая начинается со строки:
{"Name": Джон,
Самый длинный законный префикс этой фразы — «{» name «:». Таким образом, парсер JSON отметит слово John как ошибку. Парсер JSON ожидает значение в этот момент, но Джон идентификатор, который не считается значением (предположительно, автор документа забыли заключить название в кавычки).Часть, которую ожидалось «ложь», происходит из того факта, что «ложь» это последняя альтернатива производства значения в JSON грамматика. Так что это была последняя неудача на данном этапе. Пользователи, которые знают подробно о грамматике JSON может восстановить сообщение об ошибке, но для неспециалистов это сообщение об ошибке, вероятно, удивит и может также вводить в заблуждение.
Более точное сообщение об ошибке можно создать, добавив «всеобъемлющая» точка отказа как последняя альтернатива значения производство:
значение по умолчанию: Parser [Any] = obj | обр | stringLit | floatPointNumber | "ноль" | "правда" | «ложь» | сбой («недопустимое начало значения»)
Это добавление не меняет набор входных данных, которые принимаются как действительные. документы.Реализация «последней возможной» схемы ошибки. в отчетах используется поле с именем lastFailure: in trait Parsers, чтобы отметить сбой, произошедший на последняя позиция во вводе:
var lastFailure: Option [Failure] = None
Поле инициализируется значением None. Он обновлен в конструкторе класса Failure:case class Failure (msg: String, in: Input) extends ParseResult [Nothing] {
Поле читается по фразе , который выдает последнее сообщение об ошибке в случае сбоя парсера. Вот реализация фразы в трейт-парсерах:
if (lastFailure.isDefined && lastFailure.get.in.pos <= in.pos) lastFailure = Некоторые (это) }def фраза [T] (p: Parser [T]) = new Parser [T] { lastFailure = Нет def apply (in: Input) = p (in) match { case s @ Success (out, in1) => если (in1.atEnd) s else Failure ("ожидаемый конец ввода", in1) случай f: Отказ => lastFailure } }
Метод фразы запускает свой анализатор аргументов p.Если p успешно с полностью израсходованный ввод, возвращается успешный результат p. Если p завершается успешно, но ввод не читается полностью, ошибка с сообщением возвращается "ожидаемый конец ввода". Если p не работает, сбой или ошибка хранится в lastFailure, возвращается. Обратите внимание, что лечение lastFailure не работает; он обновляется как побочный эффект конструктор Failure и сам метод фразы. А возможна функциональная версия той же схемы, но требует передачи значения lastFailure, хотя каждый синтаксический анализатор результат, независимо от того, является ли этот результат успехом или Отказ.31.10 Возврат по сравнению с LL (1) [ссылка]
Комбинаторы синтаксического анализатора используют обратное отслеживание для выбора между разные парсеры в альтернативе. В выражении P | Q, если P не работает, тогда Q запускается на том же входе, что и P. Это происходит даже если P проанализировал несколько токенов до сбоя. В этом случае то же самое токены будут снова проанализированы до
кв.Отслеживание с возвратом накладывает лишь несколько ограничений на то, как сформулировать грамматика, чтобы ее можно было проанализировать. По сути, вам просто нужно избегать леворекурсивные производства.Такая продукция как:
expr знак равно выражение "+" термин | срок. всегда будет терпеть неудачу, потому что expr немедленно вызывает себя и, следовательно, никогда прогрессирует дальше. [1] С другой стороны, поиск с возвратом потенциально дорогостоящий, потому что ввод можно анализировать несколько раз. Рассмотрим, например, производство:
expr знак равно термин "+" выражение | срок. Что произойдет, если синтаксический анализатор expr применяется к входу, например (1 + 2) * 3 что составляет юридический термин? Будет испробована первая альтернатива, и потерпит неудачу при сопоставлении знака +. Тогда будет испробована вторая альтернатива на тот же срок, и это будет успешно. В конце концов срок закончился анализируется дважды.
Часто можно изменить грамматику, чтобы можно было избегали. Например, в случае арифметических выражений либо будет работать одно из следующих производств:
expr знак равно термин ["+" выражение]. expr знак равно термин \ {"+" термин \}. Многие языки допускают так называемые "LL (1)" грамматики. [2] Когда синтаксический анализатор комбинатора сформирован из такой грамматики, он никогда не будет backtrack, то есть , позиция ввода никогда не будет сброшена на более раннюю значение. Например, грамматики для арифметических выражений и терминов JSON ранее в этой главе оба являются LL (1), поэтому возможности обратного отслеживания структура комбинатора синтаксического анализатора никогда не используется для входных данных от эти языки.
Фреймворк синтаксического анализа комбинатора позволяет выразить ожидания что грамматика является LL (1) явно, с использованием нового оператора ~ !. Этот оператор похож на последовательную композицию ~, но он никогда не будет возврат к «непрочитанным» элементам ввода, которые уже были проанализированы. Используя этот оператор, результаты синтаксического анализа арифметических выражений могут в качестве альтернативы можно записать следующим образом:
def expr: Parser [Any] = срок ~! rep ("+" ~! срок | "-" ~! срок) def term: Parser [Any] = фактор ~! rep ("*" ~! фактор | "/" ~! фактор) def-фактор: Parser [Any] = "(" ~! Expr ~! ")" | floatPointNumber
Одним из преимуществ парсера LL (1) является то, что он может использовать более простой ввод техника.Входные данные можно читать последовательно, а входные элементы могут быть отбрасываются после их прочтения. Это еще одна причина, по которой парсеры LL (1) обычно более эффективны, чем парсеры с возвратом.31.11 Заключение [ссылка]
Вы ознакомились со всеми основными элементами синтаксического анализа комбинатора Scala. фреймворк. На удивление мало кода для чего-то действительно полезный. С помощью фреймворка вы можете создавать парсеры для большого класса контекстно-свободных грамматик. Фреймворк позволяет начать работу быстро, но он также может быть настроен для новых видов грамматики и ввода методы.Будучи библиотекой Scala, она легко интегрируется с остальными. языка. Так что легко интегрировать синтаксический анализатор комбинатора в большая программа Scala.
Обратной стороной комбинаторных синтаксических анализаторов является то, что они не очень эффективен, по крайней мере, по сравнению с синтаксическими анализаторами, созданными для специального назначения такие инструменты, как Yacc или Bison. На это есть две причины. Первый, метод обратного отслеживания, используемый синтаксическим анализом комбинатора, сам по себе не очень эффективный. В зависимости от грамматики и ввода синтаксического анализа он может приводят к экспоненциальному замедлению из-за повторяющегося отката.Это может быть исправлено путем создания грамматики LL (1) и использования зафиксированных последовательных оператор композиции ~ !.
Вторая проблема, влияющая на производительность синтаксических анализаторов комбинаторов: что они смешивают конструкцию парсера и анализ ввода в одном наборе операций. Фактически, синтаксический анализатор генерируется заново для каждого ввода. это проанализировано.
Эту проблему можно преодолеть, но для этого требуется другой реализация фреймворка комбинатора синтаксического анализатора. В оптимизирующем framework, синтаксический анализатор больше не будет представлен как функция из входы для анализа результатов.Вместо этого он будет представлен в виде дерева, где каждый шаг конструкции был представлен как класс case. Для Например, последовательная композиция может быть представлена классом case Seq, альтернатива по Alt и так далее. Самый "внешний" парсер метод, фраза, могли бы тогда принять это символическое представление синтаксический анализатор и преобразовать его в высокоэффективные таблицы синтаксического анализа, используя стандартные алгоритмы генератора парсеров.
Что хорошо во всем этом, так это то, что с точки зрения пользователя ничего изменения по сравнению с синтаксическими анализаторами простых комбинаторов.Пользователи все еще пишут синтаксические анализаторы с точки зрения идентификатора, числа с плавающей точкой, ~, | и т. д. Им не нужно знать, что эти методы генерируют символическое представление парсера вместо функции парсера. Поскольку комбинатор фраз преобразует эти представления в реальные синтаксические анализаторы, все работает как раньше.
Преимущество этой схемы по производительности двоякое. Во-первых, теперь вы можете исключить конструкцию парсера из анализа ввода. Если бы вы написали:
val jsonParser = фраза (значение)
а затем примените jsonParser к нескольким различным входам, jsonParser будет создаваться только один раз, а не каждый раз при чтении ввода.Во-вторых, генерация парсера может использовать эффективные алгоритмы синтаксического анализа. например LALR (1). [3] Эти алгоритмы обычно приводят к большому более быстрые парсеры, чем парсеры, которые работают с возврат.
В настоящее время такого оптимизирующего генератора парсеров еще не было. написан для Scala. Но это было бы вполне возможно. Если кто-то вносит такой генератор, интегрировать будет несложно в стандартную библиотеку Scala. Даже постулируя, что такой генератор будет существовать в какой-то момент будущее, однако есть причины для сохранения текущего парсера рамки комбинатора вокруг.Это намного легче понять а для адаптации чем генератор парсера, а разница в скорость часто не имеет значения на практике, если вы не хотите разбирать очень большие входы.
Сноски к главе 31:
[1] Есть способы избежать переполнения стека. даже при наличии левой рекурсии, но для этого требуется более совершенная структура комбинатора синтаксического анализа, которая на сегодняшний день имеет не реализовано.
[2] Aho, et. al. , г. Компиляторы: принципы, методы и инструменты .ахо-сетхи-ульман
[3] Aho, et. al. , Компиляторы: принципы, методы и инструменты . ахо-сетхи-ульман
Monadic Parser Combinators в C #
Концепция синтаксического анализа всегда казалась мне очень сложной. Я думал, что для работы в этой области нужно иметь доступ к некоторым секретным знаниям, принесенным инопланетной расой или чем-то в этом роде.
Некоторое время назад мне пришлось реализовать надлежащий разбор уценки в DiscordChatExporter, чтобы я мог заменить неэффективные регулярные выражения, которые я использовал.Я понятия не имел, как подойти к этой проблеме, поэтому потратил несколько дней на изучение этого вопроса, в конце концов узнав о комбинаторах синтаксического анализатора. Эта концепция познакомила меня с совершенно новой парадигмой написания парсеров, которая на самом деле делает его увлекательным и приятным занятием.
В этой статье я попытаюсь дать краткий общий обзор того, что такое синтаксический анализатор и что составляет формальный язык, а затем перейду к комбинаторам синтаксического анализатора, чтобы показать, насколько легко с его помощью создавать синтаксические анализаторы. Мы также напишем в качестве упражнения рабочий JSON-процессор.
Что такое парсер
Я уверен, что для большинства людей слово «синтаксический анализатор» не ново. В конце концов, мы все время «анализируем» вещи либо напрямую, например, через
int.Parse
иXElement.Parse
, либо косвенно при десериализации HTTP-ответов, чтении настроек приложения и т. Д.А что такое парсер в общем смысле этого слова?
Как люди, мы наделены множеством врожденных способностей, одна из которых - способность подсознательно деконструировать текст на логические компоненты.Это очень важный навык, потому что он позволяет нам обнаруживать закономерности, анализировать семантику и сравнивать различные фрагменты текста друг с другом.
Например, видите ли вы какую-то логическую структуру, когда смотрите на
123 456,97
? Вы легко можете сказать, что это число, состоящее из нескольких компонентов:- Цифры (
123
) - Разделитель тысяч (пробел)
- цифр (
456
) - Десятичный разделитель (
.
) - цифр (
97
)
По очевидным причинам компьютер не может обнаруживать подобные закономерности. В конце концов, он видит только кажущуюся случайной последовательность байтов:
31 32 33 20 34 35 36 2E 39 37
.Поскольку мы имеем дело с текстом, нам нужен способ его анализировать. Для этого нам необходимо программно создать тот же набор синтаксических компонентов, который мы можем видеть естественным образом:
новых SyntacticComponents [] { новый NumericLiteralComponent (123), новый компонент ThousandsSeparatorComponent (""), новый NumericLiteralComponent (456), новый DecimalSeparatorComponent ("."), новый NumericLiteralComponent (97) }
Это то, что делают парсеры. Они принимают ввод, обычно в виде текста, и формализуют его с помощью объектов предметной области. В случае неверного ввода парсер отклоняет его с информативным сообщением об ошибке.
------ (Парсер) / \ ✓ / \ X / \
Конечно, это довольно простой пример, есть гораздо более сложные языки и вводы.Но, вообще говоря, мы можем сказать, что синтаксический анализатор - это часть кода, которая может помочь построить синтаксическую структуру входного текста, эффективно помогая компьютеру «понять» его.
Считается ли ввод действительным или нет, решается набором грамматических правил, которые эффективно определяют структуру языка.
Формальная грамматика
Анализ чисел- это не ракетостроение, и вы бы не стали читать эту статью, если бы это было то, что вам нужно. Каждый может написать быстрое регулярное выражение для разделения такого текста на синтаксические компоненты.
Говоря о регулярных выражениях, знаете ли вы, почему они называются регулярными ?
В информатике есть область под названием , теория формального языка , которая конкретно занимается языками. По сути, это набор абстракций, которые помогают нам понимать языки с более формальной точки зрения.
Сам формальный язык основан в основном на концепции грамматики, которая представляет собой набор правил, которые диктуют, как создавать допустимые символы на данном языке.Когда мы говорим о допустимом и недопустимом вводе, мы имеем в виду грамматику.
В зависимости от сложности этих правил грамматики делятся на разные типы в соответствии с иерархией Хомского. На самом нижнем уровне вы найдете два наиболее распространенных типа грамматики: обычные и контекстно-свободные грамматики.
+ --------------------------------- + | | | БЕСКОНТЕКСТОВЫЕ ГРАММАТИКИ | | | | | | + -------------------- + | | | | | | | ОБЫЧНЫЕ ГРАММАТИКИ | | | | | | | + -------------------- + | + --------------------------------- +
Основное различие между ними состоит в том, что правила обычной грамматики, в отличие от контекстно-свободных, не могут быть рекурсивными.Рекурсивное грамматическое правило - это правило, которое создает символ, который может быть вычислен с помощью того же правила.
HTML - хороший пример контекстно-свободного языка, потому что элемент в HTML может содержать другие элементы, которые, в свою очередь, могут содержать другие элементы, и так далее. По этой же причине его невозможно проанализировать с помощью регулярных выражений.
В результате, в то время как ввод, который придерживается обычной грамматики, может быть представлен с использованием последовательности синтаксических компонентов, контекстно-свободная грамматика представлена с использованием структуры более высокого уровня - синтаксического дерева:
[документ HTML] | \ | \ / \ \ <основной> <нижний колонтитул> \ / | \
Итак, если мы не можем использовать регулярные выражения для построения этих синтаксических деревьев, что нам делать?
Комбинаторы синтаксического анализатора
Есть много подходов к написанию синтаксических анализаторов для контекстно-свободных языков.Большинство известных вам языковых инструментов построено либо на ручных парсерах стека циклов, либо на фреймворках генератора парсеров, либо на комбинаторах парсеров.
Комбинаторы синтаксического анализатора, как концепция, вращаются вокруг представления каждого синтаксического анализатора как модульной функции, которая принимает некоторые входные данные и выдает либо успешный результат, либо ошибку:
f (ввод) -> (результат, inputRemainder) | (ошибка)
Эти синтаксические анализаторы можно преобразовать или объединить в более сложные синтаксические анализаторы, заключив функцию в другую функцию.Вообще говоря, комбинаторы - это просто еще один класс функций, которые берут на себя другие функции синтаксического анализатора и создают более сложные.
Идея состоит в том, чтобы начать с написания синтаксических анализаторов для простейших грамматических правил вашего языка, а затем постепенно продвигаться вверх по иерархии, используя различные комбинаторы. Поднимаясь уровень за уровнем, вы в конечном итоге должны достичь самого верхнего узла, который представляет так называемый начальный символ.
Это может быть слишком абстрактным для понимания, так как насчет практического примера?
Процессор JSON с использованием комбинаторов синтаксического анализатора
Чтобы лучше понять этот подход, давайте напишем функциональный парсер JSON с использованием C # и библиотеки Sprache.Эта библиотека предоставляет набор базовых низкоуровневых синтаксических анализаторов и методов для их объединения, которые по сути являются строительными блоками, которые мы можем использовать для создания наших собственных сложных синтаксических анализаторов.
Для начала я создал проект и определил классы, которые представляют различные сущности в грамматике JSON, всего 6 из них:
-
JsonObject
-
JsonArray
-
JsonString
-
JsonNumber
-
JsonBoolean
-
JsonNull
Вот соответствующий код для них, для краткости сжатый в один фрагмент:
общедоступный абстрактный класс JsonEntity { общедоступный виртуальный JsonEntity this [имя строки] => выбросить новое исключение InvalidOperationException ($ "{GetType ().Name} не поддерживает эту операцию. "); общедоступный виртуальный JsonEntity this [int index] => throw new InvalidOperationException ($ "{GetType (). Name} не поддерживает эту операцию."); общедоступный виртуальный T GetValue
() => throw new InvalidOperationException ($ "{GetType (). Name} не поддерживает эту операцию."); общедоступный статический анализ JsonEntity (строка json) => throw new NotImplementedException («Еще не реализовано!»); } открытый класс JsonObject: JsonEntity { общедоступный IReadOnlyDictionary <строка, JsonEntity> Свойства {получить; } общедоступный JsonObject (свойства IReadOnlyDictionary ) { Свойства = свойства; } общедоступное переопределение JsonEntity this [имя строки] => Характеристики.TryGetValue (имя, результат var)? результат: ноль; } открытый класс JsonArray: JsonEntity { public IReadOnlyList Дети {получить; } общедоступный JsonArray (дети IReadOnlyList ) { Дети = дети; } публичное переопределение JsonEntity this [int index] => Children.ElementAtOrDefault (index); } общедоступный абстрактный класс JsonLiteral : JsonEntity { общественное значение TValue {получить; } защищенный JsonLiteral (значение TValue) { Значение = значение; } публичное переопределение T GetValue () => (T) Convert.ChangeType (Значение, typeof (T)); } открытый класс JsonString: JsonLiteral { public JsonString (строковое значение): base (значение) { } } открытый класс JsonNumber: JsonLiteral { public JsonNumber (двойное значение): base (значение) { } } открытый класс JsonBoolean: JsonLiteral { общедоступный JsonBoolean (значение типа bool): base (значение) { } } открытый класс JsonNull: JsonLiteral <объект> { public JsonNull (): base (null) { } } Вы можете видеть, что все наши типы JSON наследуются от класса
JsonEntity
, который определяет несколько виртуальных методов.Эти методы вызывают исключение по умолчанию, но они переопределяются правильной реализацией для типов, которые их поддерживают.Используя
JsonEntity.Parse
, вы можете преобразовать фрагмент текста JSON в объекты нашего домена и пройти всю иерархию с помощью индексаторов:var price = JsonEntity.Parse (json) ["заказ"] ["элементы"] [0] ["цена"]. GetValue
(); Конечно, это пока не сработает, потому что наш метод
Parse
не реализован.Давай исправим это.Начните с загрузки библиотеки Sprache из NuGet, затем создайте новый внутренний статический класс с именем
JsonGrammar
. Здесь мы определим грамматику для нашего языка:внутренний статический класс JsonGrammar { }
Как я объяснил выше, этот подход заключается в построении сначала простых независимых синтаксических анализаторов и постепенного продвижения вверх по иерархии. По этой причине имеет смысл начать с самой простой сущности,
JsonNull
, которая может иметь только одно значение:внутренний статический класс JsonGrammar { частный статический только для чтения Parser
JsonNull = Разобрать.Строка ("ноль"). Возврат (новый JsonNull ()); } Давайте быстро рассмотрим то, что мы здесь только что написали.
Справа от знака равенства мы вызываем
Parse.String
, чтобы создать базовый синтаксический анализатор, который будет искать последовательность символов, составляющих строку «null». Этот метод создает делегат типаParser
, но, поскольку нас не особо интересует сама последовательность символов, мы связываем ее с методом расширения> Return
, который позволяет нам указать конкретный объект для возврата. вместо.Это также изменяет тип делегата наParser
.Стоит отметить, что пока мы пишем это, синтаксический анализ еще не происходит. Мы только создаем делегат, который позже может быть вызван для анализа определенного ввода.
Если мы вызовем
JsonNull.Parse ("null")
, он вернет объект типаJsonNull
. Если мы попытаемся вызвать его на любом другом входе, он выдаст исключение с подробной ошибкой.Это круто, но пока не особо полезно.
Перейдем к
JsonBoolean
. Этот тип, в отличие отJsonNull
, на самом деле имеет два потенциальных состояния:истинное
иложное
. Мы можем обрабатывать их двумя отдельными парсерами:внутренний статический класс JsonGrammar { частный статический только для чтения Parser
TrueJsonBoolean = Parse.String ("true"). Return (new JsonBoolean (true)); частный статический только для чтения Parser FalseJsonBoolean = Разобрать.String ("false"). Return (new JsonBoolean (false)); } Это работает очень похоже на предыдущий синтаксический анализатор, который мы написали, за исключением того, что теперь у нас есть два разных синтаксических анализатора для одной сущности.
Как вы, наверное, догадались, именно здесь в игру вступают комбинаторы. Мы можем объединить эти два парсера в один, используя комбинатор
или
следующим образом:внутренний статический класс JsonGrammar { частный статический только для чтения Parser
TrueJsonBoolean = Разобрать.Строка ("истина"). Возврат (новый JsonBoolean (истина)); частный статический только для чтения Parser FalseJsonBoolean = Parse.String ("false"). Return (new JsonBoolean (false)); частный статический только для чтения Parser JsonBoolean = TrueJsonBoolean.Or (FalseJsonBoolean); } Комбинатор
или
- это метод расширения, который принимает два синтаксических анализатора одного типа и создает новый синтаксический анализатор, который завершается успешно, если один из них завершается успешно. Это означает, что если мы попытаемся вызватьJsonBoolean.Анализируя ("истина")
, мы получимJsonBoolean
, у которогоValue
равноtrue
. Точно так же, если мы вызовемJsonBoolean.Parse ("false")
, мы получимJsonBoolean
, значениекоторого
равноfalse
. И, конечно же, любой неожиданный ввод приведет к ошибке.Одна из самых крутых особенностей использования комбинаторов синтаксического анализатора - это то, насколько выразителен ваш код. На самом деле это можно прочитать буквально:
JsonBoolean имеет значение TrueJsonBoolean или FalseJsonBoolean.TrueJsonBoolean - это строка "true", которая производит JsonBoolean со значением true. FalseJsonBoolean - это строка «false», которая создает JsonBoolean, значение которого равно «false».
Чтение подобного кода позволяет легко определить структуру текста, который мы пытаемся разобрать.
Давайте обработаем следующий тип данных,
JsonNumber
:внутренний статический класс JsonGrammar { частный статический анализатор только для чтения
JsonNumber = Разобрать.ДесятичныйИнвариант .Select (s => double.Parse (s, CultureInfo.InvariantCulture)) .Select (v => новый номер JsonNumber (v)); } Как видите, Sprache уже "из коробки" предоставляет
Parse.DecimalInvariant
, который мы можем использовать для сопоставления числа. Поскольку это возвращаетParser
, когда он анализирует текст, представляющий число, нам нужно сначала преобразовать его вdouble
, а затем в наш объектJsonNumber
.Метод
Select
здесь работает аналогично методуSelect
LINQ - он лениво преобразует базовое значение контейнера в другую форму.Это позволяет отображать необработанные последовательности символов в более сложные объекты предметной области более высокого уровня.Между прочим, типы, которые имеют операцию
Select
(или, в просторечии, операцию «сопоставление»), называются «функторами». Как видите, они не ограничиваются коллекциями (например,IEnumerable
), но также могут быть контейнерами с одним значением, как и нашParser
здесь.Разобравшись с этим, перейдем к
.JsonString
:внутренний статический класс JsonGrammar { частный статический анализатор только для чтения
JsonString = из открытого в Parse.Char ('"') от значения в Parse.CharExcept ('"'). Many (). Text () из закрытия в Parse.Char ('"') выберите новый JsonString (значение); } Здесь вы можете увидеть, как мы объединили три последовательных синтаксических анализатора в один с использованием синтаксиса понимания LINQ. Вы, наверное, знакомы с этим синтаксисом при работе с коллекциями, но здесь он немного другой.
Каждая строка, начинающаяся с
из
, представляет отдельный синтаксический анализатор, который производит значение. Мы указываем имя для значения слева и определяем фактический синтаксический анализатор справа.Чтобы свести параметры к одному результату, мы заканчиваем операторомselect
, который создает нужный нам объект.Это работает, потому что связывание
из операторов
внутренне вызывает метод расширенияSelectMany
, который автор этой библиотеки определил для работы сParser
.Да, и типы, которые позволяют делать это с
SelectMany
(также известное как «плоская карта»), - это то, что мы называем «монадами».Только что написанный синтаксический анализатор попытается сопоставить двойную кавычку, за которой следует (возможно, пустая) последовательность символов, не содержащая двойных кавычек, заканчивающаяся другой двойной кавычкой, в конечном итоге возвращая объект
JsonString
с текстом внутри .Переходим к нашему первому непримитивному типу,
JsonArray
:внутренний статический класс JsonGrammar { частный статический только для чтения Parser
JsonArray = из открытого в Parse.Char ('[') от детей в JsonEntity.Token (). DelimitedBy (Parse.Char (',')) из закрытия в Parse.Char (']') выберите новый JsonArray (children.ToArray ()); } Структурно массив JSON представляет собой просто последовательность сущностей, разделенных запятыми, заключенных в пару квадратных скобок.Мы можем определить это, используя комбинатор
DelimitedBy
, который пытается сопоставить первый синтаксический анализатор, многократно разделенный вторым.Обратите внимание, что этот комбинатор принимает
Parse.Char (',')
вместо просто','
. На самом деле мы могли бы использовать вместо него более сложный синтаксический анализатор, который даже не возвращаетchar
илистроку
. В этом сила комбинаторов синтаксического анализатора - по мере того, как мы постепенно продвигаемся вверх по структуре наших данных, мы работаем с синтаксическими анализаторами все более высокого порядка.Если вы внимательно следовали приведенным здесь инструкциям, вы, вероятно, заметили, что приведенный выше код на самом деле не компилируется. Это потому, что мы ссылаемся на
JsonEntity
, который является синтаксическим анализатором, который мы еще не определили. Это потому, что это правило грамматики является рекурсивным - массив может содержать любую сущность, которая может быть, помимо прочего, массивом, который может содержать любую сущность, которая может быть массивом, что… вы понимаете.В качестве временного решения мы можем определить фиктивный объект вместо
JsonEntity
, просто чтобы он скомпилировался:внутренний статический класс JsonGrammar { частный статический только для чтения Parser
JsonArray = из открытого в Parse.Char ('[') от детей в JsonEntity.Token (). DelimitedBy (Parse.Char (',')) из закрытия в Parse.Char (']') выберите новый JsonArray (children.ToArray ()); общедоступный статический только для чтения Parser JsonEntity = null; } Также обратите внимание на метод расширения
Token ()
? Это превращает наш синтаксический анализатор в синтаксический анализатор более высокого порядка, который сразу же использует все пробелы вокруг нашего ввода. Как мы знаем, JSON игнорирует пробелы, если они не заключены в двойные кавычки, поэтому нам нужно это учитывать.Если мы этого не сделаем, наш синтаксический анализатор выдаст ошибку при обнаружении пробелов.Анализ
JsonObject
очень похож, за исключением того, что он содержит свойства вместо необработанных сущностей. Итак, сначала нам нужно начать с парсера:внутренний статический класс JsonGrammar { частный статический только для чтения Parser
> JsonProperty = от имени в JsonString.Select (s => s.Value) из двоеточия в Parse.Char (':').Токен () от значения в JsonEntity выберите новый KeyValuePair <строка, JsonEntity> (имя, значение); частный статический только для чтения Parser JsonObject = из открытого в Parse.Char ('{') из свойств в JsonProperty.Token (). DelimitedBy (Parse.Char (',')) из закрытия в Parse.Char ('}') выберите новый JsonObject (properties.ToDictionary (p => p.Key, p => p.Value)); } Поскольку наша модель реализует
JsonObject
с использованием словаря, отдельное свойство выражается с помощьюKeyValuePair
, то есть имени свойства (string
) и его значения (JsonEntity
).Как видите, мы снова использовали синтаксис понимания LINQ для объединения последовательных синтаксических анализаторов.
JsonProperty
состоит изJsonString
для имени, двоеточия иJsonEntity
, обозначающего его значение. Мы используемSelect ()
наJsonString
для ленивого извлечения только необработанного значенияstring
, поскольку нас не интересует сам объект.Для парсера
JsonObject
мы практически написали тот же код, что и дляJsonArray
, заменив квадратные скобки фигурными скобками иJsonEntity
наJsonProperty
.Наконец, закончив с каждым отдельным типом сущности, мы можем правильно определить
JsonEntity
, объединив синтаксические анализаторы, которые мы написали ранее:внутренний статический класс JsonGrammar { общедоступный статический только для чтения Parser
JsonEntity = JsonObject .Или (JsonArray) .Or (JsonString) .Или (JsonNumber) .Или (JsonBoolean) .Or (JsonNull); } И обновите статический метод, который у нас есть в самом классе
JsonEntity
, чтобы он вызывал соответствующий парсер:публичный абстрактный класс JsonEntity { общедоступный статический анализ JsonEntity (строка json) => JsonGrammar.JsonEntity.Parse (json); }
Вот и все, JSON-процессор у нас рабочий! Теперь мы можем вызвать
JsonEntity.Parse
для любого допустимого текста JSON и преобразовать его в наш домен, то есть в дерево изобъектов JsonEntity
.Завершение
Разборне должен быть сложной и недоступной задачей. Функциональное программирование помогает нам моделировать сложную грамматику как композицию более мелких функций, о которых довольно легко рассуждать. И, к счастью, мы можем сделать это и на C #!
Если вы все еще жаждете знаний и хотите увидеть немного более сложный пример, обратите внимание на LtGt, обработчик HTML (с селекторами CSS!), Который я изначально написал с использованием Sprache.
Если вы хотите узнать больше о синтаксическом анализе в целом, я рекомендую прочитать статью Габриэле Томассетти «Анализ в C #».
Есть также другие библиотеки комбинаторов монадического синтаксического анализатора в .NET, которые вы можете проверить, в первую очередь Superpower, Pidgin, Parsley и FParsec (F #).
Эта статья в значительной степени основана на моем выступлении с .NET Fest 2019 «Комбинаторы монадического синтаксического анализатора в C #». Здесь вы можете найти исходную презентацию и полный исходный код парсера JSON.
Подходы к разрыву строки
Подходы к разрыву строкиЦелевая аудитория: разработчики браузеров, разработчики спецификаций и все, кто хотел бы получить лучшее представление о том, чем различаются полные разрывы строк и перенос текста в системах письма по всему миру.
В этой статье дается общий обзор различных типографских стратегий для переноса текста в конец строки для различных сценариев.
Разрыв строки часто предшествует выравниванию текста.Для аналогичного обобщения подходов к обоснованию см. Подходы к полному обоснованию.
В этой статье представлен широкий обзор различных стратегий, используемых разными системами письма, но это только обзор. Особые правила применяются практически ко всем сценариям, влияющим на то, какие символы могут начинать или заканчивать строку, а какие - нет. Некоторые системы письма позволяют переносить слова, а другие - нет. Мы будем приводить только примеры основных отличий, а не исчерпывающе перечислять все детали.
Для получения более подробной информации о том, как происходит разрыв строки в различных сценариях, см. Международный указатель макета текста и типографики.
Самый фундаментальный алгоритм, используемый для переноса текста в конец строки, зависит от слияния двух факторов:
- разделены ли в тексте «слова» или слоги, и если да, то как и
- , переносит ли система письма слова, слоги или символы в следующую строку.
Что такое слово?
Очень сложно дать четкое определение термина « слово », и все же различие между словами и слогами имеет важное значение в некоторых языках для целей разрыва строки.
Часто приложения и алгоритмы предполагают, что слово - это последовательность символов, разделенных пробелом, или иногда какой-либо другой знак пунктуации. Некоторые языки, однако, написаны с использованием сценариев, которые только разграничивают слоги, но все же рассматривают слова как единицы, состоящие из одного или нескольких слогов (например, тибетский и вьетнамский). Другие вообще не идентифицируют визуально границы слов или слогов, но поддерживают различие между словами и слогами (например, кхмерский, который обычно не разделяет визуально ни то, ни другое внутри фразы, но сильно склонен рассматривать слова как базовую единицу. при переносе строк, а не слогов или символов).
Даже если слово предполагается для определенного набора языков как последовательность букв, ограниченных пробелами, с лингвистической точки зрения это скрывает некоторые существенные основные различия и сложности. Состав этих слов может значительно отличаться от языка к языку. Например,
- слов в финском языке могут оканчиваться несколькими предложными или другими суффиксами, прикрепленными к основному слову (talo означает «дом», а talostani - «из моего дома»),
- слов на немецком языке могут быть составными, состоящими из последовательности меньших слов, таких как Eingabeverarbeitungsfunktionen, которое является составным из слов Eingabe, Verarbeitung и Funktion, за которыми следует маркер множественного числа,
- на арабском языке маленькие слова, такие как 'и' (و), пишутся рядом со следующим словом без пробелов (например,الجامعات والكليات означает «университеты и колледжи», но есть только одно место).
Когда «разделители слов» отсутствуют в таких языках, как кхмерский, тайский, японский и т. Д., Определение того, что составляет слово, может быть субъективным, если речь идет о составных существительных или грамматических частицах. Например, тайский перевод слова «письмо» การ เขียน можно рассматривать как одно слово (kānkhīan) или как два (kān khīan).
Для целей этой статьи мы не будем пытаться давать слишком точное определение термину «слово».Вместо этого мы просто будем использовать его для обозначения нечетко определенной семантической единицы, которая может включать один или несколько слогов.
Широкие типы
В следующей таблице представлен общий обзор факторов, влияющих на то, как система письма переносит текст в конец строки. Комбинации язык + сценарий, перечисленные в таблице, являются лишь примерами и относятся только к системам письма, которые используются в настоящее время. Если за именем языка не следует имя сценария, и язык, и сценарий имеют одно и то же имя.Обратите внимание, что для данного языка обычно используется более одного сценария.
Обратите также внимание на то, что некоторые комбинации языка и сценария (со звездочками) появляются более чем в одном месте в таблице, указывая на то, что существуют альтернативные подходы. Причины этого описаны позже.
Пробел как разделитель слов Другой разделитель слов Разделитель слогов Без разделителя Обертывание слов Амхарский (эфиопский) *, арабский, армянский, бенгальский, чероки, дивехи (тхана), английский (латинский), английский (десерет), фула (адлам), грузинский, греческий, гуджарати, иврит, хинди (деванагари), инуктитут ( UCAS), каннада, корейский (хангыль) *, малаялам, мандайский, мандинка (нько), ория, панджаби (гурмухи), русский (кириллица), сингальский, сирийский, тамильский, тедим (пау чин хау), телугу Самаритянин Кхмерский, Лаосский, Мьянма, Тайский Обертывание слогов Восточно-чамский, корейский (хангыль) *, сунданский Вьетнамский (латиница), тибетский балийский, батакский, китайский, яванский, западно-чамский Обтекание символов Амхарский (эфиопский) * Японский, Вай Архаичные сценарии гораздо чаще используют подход scriptiocontina (т. Е.без разрывов слов или слогов), хотя в современных текстах, описывающих их, вы можете встретить пробелы, разделяющие единицы текста. В более старых версиях упомянутых скриптов также могут использоваться другие правила для разделения слов и разрыва строки.
В следующих разделах мы дадим примеры основных альтернатив и упомянем некоторые последствия. Мы сосредоточимся только на современном использовании, и отложим упоминание о переносах на потом.
Слова, разделенные пробелами
Это подход, с которым знакомо большинство людей, и именно так работает английский текст в этой статье.Когда достигается конец строки, приложение обычно ищет предыдущий пробел, который считается разделителем слов, и переносит все после него на следующую строку *.
Многие скрипты работают именно так. Среди прочего, они включают скрипты, используемые для всех основных европейских языков, включая кириллицу и греческий; скрипты, используемые для основных индийских языков, таких как деванагари, гуджарати и тамильский; скрипты, используемые для современных семитских языков, таких как арабский, иврит и сирийский; и сценарии, используемые для американских языков, такие как Cherokee и Unified Canadian Syllabic (UCAS).
Возможности разрыва строки в тексте на хинди (сценарий деванагари).Языки, написанные с письмом справа налево, например арабский, иврит или дивехи, также обычно переносят полные слова на следующую строку. Однако они делают это, конечно, в противоположном направлении, скажем, от английского.
Возможности разрыва строки для арабского текста.Однако текст на таких языках, как арабский, иврит или дивехи, значительно усложняется, если он содержит двунаправленный текст.Если мы сделаем текст «... في this is English لك ...» в приведенном выше примере, мы получим следующее.
Перенос встроенного текста противоположного направления на арабском языке.Посмотрев на приведенный выше пример, вы заметите, что относительный порядок английских слов был изменен на разрыв строки. Это связано с тем, что горизонтальный двунаправленный текст никогда не читается вверх, от строки к строке. Этот вывод управляется процессом двунаправленного переупорядочения до того, как рассчитываются возможности разрыва строки, и влияет только на расположение глифов шрифта.Символы в памяти идут в порядке произношения и не меняются.
Вертикально установленные китайский, японский, корейский и традиционный монгольский языки переносят слова вверх, но новая строка появляется слева для CJK и справа для монгольского.
Юго-Восточная Азия: без разделителя слов
Тайский, лаосский и кхмерский языки пишутся без пробелов между словами. Пробелы встречаются, но они служат в качестве разделителей фраз, а не слов. Однако, когда текст на тайском, лаосском или кхмерском достигает конца строки, ожидается, что текст будет переноситься по слову за раз.Для людей это не слишком сложно (если вы говорите на этом языке), но приложения должны найти способ понять текст, чтобы определить, где находятся границы слов.
Возможности разрыва строки в кхмерском тексте.Большинство приложений делают это с помощью поиска по словарю. Он не идеален на 100%, и авторам может потребоваться время от времени что-то корректировать. Например, вот два альтернативных набора возможностей разрыва строки в тайской фразе.
Альтернативные возможности разрыва строки для тайского текста.Разница здесь не только в ошибочных реализациях. Как упоминалось ранее, понятие слова в системах письма, которые не разграничивают их четко, довольно подвижно. Вышеуказанные различия возникают из-за различных субъективных мнений о том, следует ли переносить составные слова целиком или нет на следующую строку.
В прошлом символ Юникода U + 200B ZERO WIDTH SPACE (ZWSP) использовался для обозначения границ слов для этих сценариев, а некоторые стандартные клавиатуры, такие как кхмерский NIDA, по-прежнему генерируют ZWSP с помощью клавиши пробела, но в последнее время в основных языках есть строчные- в их распоряжении есть ломающие реализации, что означает, что ZWSP не важен.Крупномасштабный ручной ввод ZWSP также не очень практичен, потому что пользователь не может видеть разделитель в большинстве сценариев; это приводит к проблемам с ZWSP, вставленным в неправильном месте или несколько раз. Однако ZWSP можно использовать для ручной работы и исправления некоторых аспектов поведения прерывания строки.
Также важно иметь в виду, что упомянутые здесь скрипты могут использоваться для написания языков, отличных от упомянутых, в частности языков меньшинств, для которых необходимы другие словари.Поскольку такие словари могут быть недоступны в данном браузере или другом приложении, существует тенденция использовать ZWSP для компенсации.
Некоторые системы письма переносят в следующую строку не только слова, но и слоги. Часто предпочтительнее переносить слова целиком, но вместо этого текст также может быть разбит на границы слога.
Как правило, требуется некоторый анализ текста, чтобы определить, где встречаются границы слогов. Часто конец слога обозначается последней согласной, которая является объединяющим символом, или конец слога может быть обозначен специальным знаком, однако в некоторых случаях расположение границ слога может быть визуально неоднозначным.Более того, рассматриваемый слог может быть орфографическим, а не фонетическим слогом (см. Ниже).
Сюда включеныкитайского и корейского языков, хотя они немного необычны тем, что слог обычно соответствует одному символу, а не последовательности. (Хотя в тех редких случаях, когда корейский язык хранится как хамос, а не как слоговые символы, присутствует последовательность.)
Тибетский: видимые разделители слогов
Хорошим примером системы письма, которая регулярно ломается на границах слога, является тибетский, в котором для обозначения конца слога используется ་ [U + 0F0B TIBETAN MARK INTERSYLLABIC TSHEG] (произносится как цек).
Тибетский оборачивается путем переноса полных слогов на следующую строку, так что исходная строка заканчивается знаком цек. Тибетские слова могут состоять из нескольких слогов, и хотя предпочтительно избегать разрывов строки в середине слова, это не обязательно. С другой стороны, слог всегда следует сохранять нетронутым.
Возможности разрыва строки на тибетском языкеКорейский хангыль: альтернативы
Корейский необычен тем, что слова в современном тексте хангыль обычно разделяются пробелами, но система письма позволяет авторам контента выбирать один из двух способов переноса этого текста.
Перенос по слогам является обычным явлением, особенно в полностью выровненном тексте (что чаще встречается в системах письма CJK , чем в западных), но абзацы с рваным правым краем часто переносят целые слова. Однако выбор мотивирован предпочтениями автора, а не каким-либо жестким правилом.
Вы также можете встретить хангыль, написанный без пробелов между словами (например, китайский и японский), особенно в старых текстах.
Альтернативные возможности разрыва строки для корейского текста хангыль.Мы могли бы описать хангыль как обертку на основе символов, а не слогов. Слоговая система особенно подходит, когда корейский текст хранится как джамо, однако подавляющее большинство корейского текста хранится как слоговые символы.
Суданский язык, восточно-чамский язык: пробел как разделитель слов
Мы видели, что в корейском тексте используются пробелы между словами, но не обязательно использовать эти пробелы для обозначения возможности переноса строки. Есть и другие системы письма, которые также разделяют слова пробелами, но могут переносить слоговые единицы.В отличие от корейского, в котором обычно используется символ за символом, в этих системах письма в качестве единицы текста используется последовательность символов, соответствующая слогу.
Возможности разрыва строки в сунданском тексте.Больше из Юго-Восточной Азии: без разделителя слов
Ряд других письменностей Юго-Восточной Азии написаны без пробелов между словами. В этих системах письма вы также можете обнаружить, что текст переносится по границам слогов в дополнение к границам слов.
Возможности разрыва строки в яванском тексте.Возможности разрыва, показанные выше для яванского языка, соответствуют орфографическим слогам, а не фонетическим. Например, если один фонетический слог заканчивается согласной, а следующий слог начинается с согласной, они могут быть сложены или соединены особым образом. Эти комбинации не разделяются. Во многих сценариях эти особые союзы могут встречаться только внутри слов, но в других (таких как яванский и балийский) они могут фактически перекрывать границы слов.
Разные цвета представляют два яванских слова pangan и dika , но возможность разрыва (красная линия) появляется перед стеком, отсекая последнее n от предыдущего слова.В тех случаях, когда система письма может представлять согласные в конце слога с помощью комбинированного символа, они обычно рассматриваются как часть предшествующего орфографического слога.
В этих языках обычно символы переносятся на следующую строку, независимо от границ слога или слова.Однако это небольшое упрощение, как мы увидим здесь и в следующих разделах, потому что обычно существуют правила о том, где может отображаться пунктуация, которые влияют на возможность переноса строки, и некоторые соседние символы могут оставаться вместе.
Японский и вайский: упаковка на основе мора
Японский и вайский обычно переносят отдельные символы в следующую строку, независимо от границ слова или слога.
Возможности разрыва строки в японском тексте.Этот тип переноса иногда называют слоговым, но на самом деле японский язык основан на морали, а не на слогах. Например, можно найти текст, заключенный в один слог き ょ う (произносится как kyō, что означает «сегодня»).
Тем не менее, все (как всегда) не так однозначно. Хотя принято переносить последний из трех символов в слове き ょ независимо от следующей строки, некоторые авторы контента предпочитают всегда оставлять маленький второй символ вместе с первым.CSS предоставляет
строгий
исвободный
значений для свойстваразрыва строки
, чтобы авторы контента могли контролировать это поведение. Последнее значение допускает перенос строки между ними. Это часто может быть полезно для текста в узких столбцах, например газет.Кроме того, иногда возникают ситуации, например, в заголовках, когда автор контента может предпочесть заключить в перенос, не разделяя то, что воспринимается как «слова». Однако обратите внимание, что в японском языке составные слова часто строятся из отдельных слов, а японский добавляет грамматические частицы после слов, которые могут или не могут рассматриваться как тесно связанные со словом.Таким образом, что касается тайского языка, это может быть довольно субъективным в отношении того, что составляет границу слова в японском языке.
В некоторых случаях перенос на основе символов, используемый для китайского и японского языков, также применяется к встроенному латинскому тексту. Когда такой встроенный текст переносится, границы слогов и переносов не принимаются во внимание. Аналогичным образом, можно ожидать, что текст на японском и китайском, встроенный в латинский текст, будет переноситься как единое целое. (Этим поведением можно управлять с помощью свойств CSS.)
Эфиопский: разделитель слов без пробела
В современном эфиопском тексте могут использоваться пробелы между словами, и в этом случае ожидается, что все слово будет перенесено на следующую строку как единое целое.
Возможности разрыва строки на амхарском языке, когда слова разделены пробелами.Тем не менее, эфиопский текст может также использовать традиционный символ пространства слов ፡ [U + 1361 ETHIOPIC WORDSPACE] для обозначения границ слов. В этом случае слово Ethiopic переносится после любого символа, если пробел не появляется в начале строки.
Непробельные разделители слов также часто встречаются в архаичных сценариях.
Возможности разрыва строки на амхарском языке, когда слова разделены эфиопским символом пробела.Конечно, как и в случае с другими символами переноса строки, есть и другие правила, которые следует учитывать. Например, предпочтительно ставить перед пробелом слова как минимум два символа в начале строки, а знаки препинания в начале и конце строки могут повлиять на поведение разрыва строки по умолчанию (см. Ниже).
Расстановка переносов - это механизм, который помогает лучше уместить текст в строке. Только подмножество систем письма поддерживает расстановку переносов, но в основном это необходимо для разбиения слов на более мелкие единицы для переноса.
Важно отметить, что правила расстановки переносов различаются от языка к языку в рамках одного и того же сценария. Хотя оба используют латинский шрифт, правила орфографии на немецком и английском языках могут сильно отличаться. Контент на арабском языке обычно не допускает переносов, в отличие от уйгурского, хотя оба они используют арабскую графику. (Обратите внимание, что арабский язык предоставляет ряд альтернативных методов удлинения или сокращения линий во время выравнивания.)
Механизм расстановки переносов также различается.Для некоторых языков дефис (который может не выглядеть как «-») появляется в начале следующей строки, в других - в обеих строках. В некоторых случаях написание слова изменяется вокруг расстановки переносов, например, в голландском cafeetje → café-tje и skiërs → ski-ers , а на венгерском Összeg → Ösz-szeg .
В других сценариях текст может иногда прерываться внутри слова, но дефис не используется для обозначения разрыва.
Пунктуация
Приведенный выше японский пример ясно показывает, как часто запрещается перенос строки перед определенными знаками препинания. Для большинства скриптов характерно, что содержимое не должно начинаться с строки со знаком препинания, который показывает конец фразы или раздела.
Другие знаки препинания обычно не должны завершать строку. К ним относятся открывающие круглые скобки или квадратные скобки.
В этих обстоятельствах приложение обычно ищет предыдущую возможность разрыва строки и переносит знак препинания и предшествующий текст в следующую строку вместе.
Возможно, нет необходимости переносить символ пунктуации в следующую строку, если можно сократить пространство вокруг других символов в строке во время выравнивания, тем самым оставляя место для его размещения.
Если это невозможно, альтернативная стратегия, которую иногда можно встретить в таких языках, как японский и китайский, заключается в том, чтобы оставить знаки препинания за пределами поля в конце строки. (Очевидно, это работает только при наличии видимого поля.)
Висячие знаки препинания в японском тексте.Предотвращение разрывов строк
В некоторых ситуациях требуется механизм для предотвращения разрывов строк. Это может быть особенно полезно, когда последовательность символов в очень короткой строке не имеет возможности естественного разрыва строки, но также может быть полезно в других ситуациях, когда вы хотите настроить поведение .
Unicode имеет набор правил для определения кластеров графем по умолчанию, которые указывают последовательности символов, которые обычно не должны разделяться разрывом строки.Например, сюда входит любой комбинированный символ, следующий за базовым символом. Однако его также можно расширить, чтобы предотвратить разрывы в многосимвольных слогах, например, в индийских алфавитах или шрифтах Юго-Восточной Азии.
В Юникоде также есть символы, которые склеивают смежные символы, включая такие символы, как U + 00A0 NO-BREAK SPACE и U + 2011 NON-BREAKING HYPHEN, а также для ситуаций, когда вы хотите предотвратить разрыв строки, невидимое СЛОВО U + 2060 СОСТАВНИК.
Мы уже упоминали режим
strict
, который используется для объединения определенных символов в японском языке.Разметка или стиль также могут использоваться для отмены нормального поведения при нарушении правил. Например, в заголовках иногда предпочтительнее разрывать границы слов на японском языке, чтобы избежать появления небольшого количества символов на новой строке. Для этого можно использовать укладку.Другие особые правила
В дополнение к правилам о том, какой символ может или не может появляться в конце / начале строки, могут быть более сложные правила, связанные с процессом переноса текста.
Здесь мы приводим в качестве примера некоторые подробности о переносе строк в традиционных тибетских форматах.В тибетском языке U + 0F0D TIBETAN MARK SHAD 1 используется как разделитель фраз, а двойной шай - разделитель темы. Если только один слог перед шаем переходит в новую строку, шай (или первый шай, если их два) заменяется на U + 0F11 TIBETAN MARK RIN CHEN SPUNGS SHAD 2 . В конце темы правила гласят, что конвертировать следует только один шай, однако умеренно популярно конвертировать оба. Это изменение служит оптическим указанием на то, что в начале строки есть оставшийся слог, который фактически принадлежит предыдущей строке.
1) ТЕНЬ (произносится как шай)
2) RIN CHEN SPUNGS SHAD
.1)
2)
Двойная насадка возле конца лески в (1) превращается в двойную рин чен спанг, когда она завернута в (2).Различается в следующих случаях:
- когда строка начинается с le'u 3 , не будет использоваться rin chen spungs shad , поскольку le'u произносится как два слога.
- Иногда, если заменяется только первый из двух шей, этот стиль считается менее привлекательным.
- некоторые печатные книги не используют замену rin chen spungs shad , однако в большинстве книг, похоже, применяются те же правила, что и для pechas.
3) лей
В заключение, иллюстрация особого поведения в яванском сценарии. Когда новая строка начинается с U + A9BA JAVANESE VOWEL SIGN TALING 4 , идентичный глиф интервала помещается в конец предыдущей строки. Важно отметить, что в памяти есть только один символ таллинга: первый глиф - это просто призрак.
4) РАССКАЗ
Глиф таллинга появляется в конце и начале строки, когда слово кавон разделяется до того, как выиграл.Это не часто встречается в современном тексте, хотя это не так уж удивительно, поскольку для его создания необходим довольно специальный алгоритм. При использовании старых методов установки шрифтов это (и тибетский пример выше) было бы относительно легко создать, добавив некоторый тип в конец статической строки типа. Однако веб-страницы являются динамическими, и ширина строки может измениться в любое время, поскольку пользователь изменяет размеры окна браузера.Показанное поведение должно быть реализовано только тогда, когда разрыв оказывается точно в нужном месте: по мере перекомпоновки текста при изменении ширины окна браузера лишний тейлинг должен исчезнуть.
Создание слов и фраз в левой височной доле
Abstract
Центральная часть знания языка - это способность комбинировать базовые языковые единицы для формирования сложных представлений. Хотя наше нейробиологическое понимание того, как слова объединяются в более крупные структуры, значительно продвинулось в последние годы, комбинаторные операции, которые создают сами слова, остаются неизвестными.Созданы ли сложные слова, такие как tombstone и starlet , с помощью тех же механизмов, которые строят фразы из слов, таких как серый камень или яркая звезда ? Здесь мы обратились к этому с помощью двух экспериментов по магнитоэнцефалографии (МЭГ), которые одновременно меняли требования, связанные с фразовым составом и обработкой морфологической сложности в составных и суффиксных существительных. Повторяя предыдущие результаты, мы показываем, что части левой передней височной доли (LATL) задействованы в сочетании модификаторов и мономорфных существительных во фразах (например,г., коричневый кролик ). Что касается компаундирования, мы показываем, что семантически прозрачные соединения (например, надгробная плита ) также задействуют левую переднюю височную кору, хотя пространственно-временные детали этого эффекта отличались от фразового состава. Кроме того, когда фраза была построена из модификатора и прозрачного соединения (например, гранитное надгробие ), типичный ответ фразовой композиции LATL появлялся с задержкой, которая возникает, если начальная операция в пределах слова ( могила + камень ) должно произойти перед объединением соединения с предыдущим модификатором ( гранит + надгробие ).В отличие от компаундирования, суффиксирование (например, звездочка + let ) никак не взаимодействует с LATL, что предполагает отдельный путь обработки. Наконец, наши результаты предлагают интригующее обобщение, что морфо-орфографическая сложность, которая не задействует LATL, может блокировать участие LATL в последующем построении фраз.