2012-06-26 4 views
2

Я пытался найти примеры повсюду, но это было напрасно.анализ проверки семантического типа в bison

Я пытаюсь написать базовый интерпретатор Ruby. Для этого я написал лексический файл flex, содержащий предложения распознавания токенов и файл грамматики.

Я хочу, чтобы моя грамматика содержала проверку семантического типа.

Моего файл грамматика содержит, например:

arg : arg '+' arg 

Это должно быть действительным правилом для целых и поплавков.

Согласно тому, что я прочитал, я могу указать тип для не терминала, такие как Arg, например, так:

%type <intval> arg 

где «intval» находится в типе объединения и соответствует типу INT C ,

Но это только для целых чисел, я не уверен, как сделать правило действительным, скажем, поплавком. Я думал о наличии двух различных правил, один для целых чисел и один для поплавков, как:

argint : argint '+' argint 
argfloat : argfloat '+' argfloat 

, но я уверен, что есть намного лучший способ сделать это, так как это зверство потребовало бы, чтобы у меня правила для добавления дополнений между float и int.

Все примеры, которые я нашел, имеют только один тип (обычно целые числа в калькуляционных примерах).

Как я могу добиться указания того, что правило, такое как добавление, может иметь ints и floats в качестве аргументов?

спасибо.

+0

Вы неправильно поняли цель типа%. Он предназначен для управления типами собственных грамматических терминалов и нетерминалов для использования в YYUNION, поэтому вам не нужно писать typecasts для ваших $$, $ 1 и т. Д .: не позволять вам управлять семантическими типами в программе, которую вы разбираете. – EJP

ответ

4

Это не тот ответ, на который вы надеетесь. Я думаю, причина, по которой вы не видели примеров того, чего вы хотите, заключается в том, что нецелесообразно применять правила набора текста в файле грамматики (.y); скорее, разработчики выполняют это в процедурном коде .c или .cpp. Как правило, в любом случае вы будете проводить анализ анализируемого ввода, поэтому это побочный продукт для обеспечения соблюдения семантических правил, как вы это делаете.

В стороне, я не совсем понимаю, как вы разбираете выражения, учитывая фрагмент вашей грамматики, который вы воспроизводите в своем вопросе.

Вот почему я утверждаю, что это непрактично. (1) Ваша информация о типе должна просачиваться через не-терминалы грамматики. (2) Хуже того, это должно быть отражено в именах переменных.

Рассмотрим этот игрушечный пример анализа простых операторов присваивания, которые могут использовать идентификаторы, числовые константы и четыре оператора настольного калькулятора. Маркер NUMBER может быть целым числом, равным 42, или плавающим, как 3.14. И скажем, что IDENTIFIER - это одна буква, A-Z.

%token IDENTIFIER NUMBER 

%% 

stmt : IDENTIFIER '=' expr 
    ; 

expr : expr '+' term 
    | expr '-' term 
    | term 
    ; 

term : term '*' factor 
    | term '/' factor 
    | factor 
    ; 

factor : '(' expr ')' 
     | '-' factor 
     | NUMBER 
     | IDENTIFIER 
     ; 

Теперь давайте попробуем ввести правила набора текста. Мы разделим токен NUMBER в FLT_NUMBER и INT_NUMBER.Наши expr, term и factor нетерминалы разделить на две части, а также:

%token IDENTIFIER FLT_NUMBER INT_NUMBER 

stmt : IDENTIFIER '=' int_expr 
    | IDENTIFIER '=' flt_expr 
    ; 

int_expr : int_expr '+' int_term 
     | int_expr '-' int_term 
     | int_term 
     ; 

flt_expr : flt_expr '+' flt_term 
     | flt_expr '-' flt_term 
     | flt_term 
     ; 

int_term : int_term '*' int_factor 
     | int_term '/' int_factor 
     | int_factor 
     ; 

flt_term : flt_term '*' flt_factor 
     | flt_term '/' flt_factor 
     | flt_factor 
     ; 

int_factor : '(' int_expr ')' 
      | '-' int_factor 
      | INT_NUMBER 
      | int_identifier 
      ; 

flt_factor : '(' flt_expr ')' 
      | '-' flt_factor 
      | FLT_NUMBER 
      | flt_identifier 
      ; 

int_identifier : IDENTIFIER ; 

flt_identifier : IDENTIFIER ; 

Поскольку наша грамматика стоит в этой точке, возникает конфликт: синтаксический анализатор не может сказать, следует ли признавать IDENTIFIER как int_identifier или a flt_identifier. Поэтому он не знает, следует ли уменьшить A = B как IDENTIFIER = int_expr или IDENTIFIER = flt_expr.

(Здесь мое понимание Ruby немного мягкое :) Ruby (как и большинство языков) не предоставляет способ на лексическом уровне для определения числового типа идентификатора. Сравните это со старой школой BASIC, где A обозначает число, а A $ обозначает строку. Другими словами, если вы изобрели язык, где, скажем, A # обозначает целое число, а A @ обозначает float, то вы можете сделать эту работу.

Если вы хотите разрешить ограниченные выражения смешанного типа, например int_term '*' flt_factor, то ваша грамматика станет еще сложнее.

Могут быть способы обойти эти проблемы. Парсер, построенный по технологии, отличной от yacc/bison, может упростить работу. По крайней мере, возможно, мой эскиз даст вам несколько идей, чтобы продолжить.

+0

Хороший ответ. Идея построения семантики типа в грамматике была всесторонне взорвана проектом Алгол-68, да, в 1960-х годах. В настоящее время общепризнано, что оно является недопустимым. – EJP

+0

Да, это то, что я закончил делать, в конце концов, мне еще предстоит решить, как проверить тип возвращаемой функции, но это в основном то, что я сделал, спасибо! –

+0

Это [Закон Вадлера] (http://www.haskell.org/haskellwiki/Wadlers_Law) ... но остается немного грустно, что даже до сегодняшнего дня только синтаксис языка формализуется в коде (через BNF), а не семантику (через vWG). – NevilleDNZ