Курсовая работа: Совместимость и преобразование типов данных
5. Если нетерминалу t соответствует базовый тип ref(tid(I,B)), а типу tid(I,B) уже сопоставлен нетерминал t1, то вводится правило t -> ^ t1.
Нетерминалы этой грамматики эквивалентны, если и только если соответствующие типы структурно эквивалентны.
Остаётся преобразовать эту грамматику к автоматному виду и применить алгоритм нахождения всех пар эквивалентных состояний.
Отношение структурной эквивалентности действительно является эквивалентностью, т.к. оно рефлексивно, транзитивно и симметрично. Кроме того, два типа структурно эквивалентны тогда и только тогда, когда они допускают одни и те же последовательности операций. Это делает такую эквивалентность простой и понятной программистам. Её основным и весьма существенным недостатком является сложный и громоздкий алгоритм проверки эквивалентности. Насколько известно автору, структурная эквивалентность была принята только в языке Алгол 68.
Предикат consist в этом случае определим следующим образом:
consist(T1,T2):base_type(T1,BT1),base_type(T2,BT2),
(BT1=int,BT2=real ; % приводимость
equiv(BT1,BT2) ; % эквивалентность
error("Несовместимые типы")).
Именная эквивалентность
При стандартизации языка Паскаль была принята именная эквивалентность. Согласно её определению эквивалентными могут быть только именованные типы, т.е. типы с атрибутами int, real или tid(_,_):
1. Именованный тип эквивалентен сам себе.
2. Если тип T=tid(I,B) имеет описание declared(I,B,T1), где T1 – именованный тип, то типы T и T1 эквивалентны.
Это очень ограничительное определение. Даже в Паскале допустимо присваивание
U:=V,
если переменные U и V описаны как
var U,V: array[1..10]of real,
хотя имеют неименованный тип "массив". Но в том же Паскале этот оператор недопустим из-за неэквивалентности типов переменных, если они описаны как
var U: array[1..10]of real;
var V: array[1..10]of real;
Чтобы охватить все эти случаи, компилятор для каждого вхождения выражения типа, начинающегося с array, record или ^ (т.е. не являющегося идентификатором типа), вводит уникальное имя типа – псевдоним, благодаря чему разные вхождения одного и того же выражения типа оказываются неэквивалентными в смысле именной эквивалентности.
В соответствии со сказанным следует внести изменения в правила DC-грамматики для нетерминала type, определяющие атрибут типа. В них включается теперь порождение и описание псевдонимов типа. Для генерации новых "имен" можно использовать самые разные методы; мы здесь воспользуемся предикатом recorda, генерирующем в качестве псевдонима уникальную ссылку на пустой терм, записываемый по ключу alias. описание этого псевдонима типа включается в виде предиката declared.
type(B,tid(A,B)) -->
[array,`[,n(M),`:,n(N),`],of],type(B,T),
{recorda(alias,_,A),
assert(declared(A,B,type(arr(M,N,T)))}.
type(B,tid(A,B)) -->
[record],field(B,F),fields(B,LF),
{correct(F,LF),