Оценка короткого замыкания с использованием процедур - PullRequest
4 голосов
/ 27 февраля 2012

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

Во время компиляции я преобразовываю целочисленные литералы в объекты специального класса "Integer". Арифметические операторы реализованы как методы этого класса (с использованием встроенного ассемблера). Так что 4 + 5 в основном равно 4.add(5).

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

if(10 > 5 || 12 < 10)

в настоящее время это будет преобразовано в: 10.greaterThan(5).or(12.lessThan(10))

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

Итак, мои вопросы:

  1. Как другие языки достигают оценки короткого замыкания, но все равно рассматривают каждое значение как объект?

  2. Согласно Википедии «АЛГОЛ 68 использовал« процедуры »для достижения определенных пользователем операторов и процедур короткого замыкания». - Как это работает?

Ответы [ 3 ]

4 голосов
/ 27 февраля 2012

Обычная техника, я полагаю, включает либо вызов по имени , либо вызов по необходимости . Идея состоит в том, что параметр or не является результатом сравнения, а само сравнение преобразуется в thunk , который всякий раз преобразуется в значение результата (при вызове по имени) или в первый раз (по требованию) это необходимо.

При преобразовании выражения в thunk вы в основном создаете анонимную функцию, и вы можете рассматривать проблему компиляции как таковую. Это включает компиляцию выражения в код, который будет оценивать выражение. Это также включает создание объекта (самого thunk), который ссылается (или содержит копии) на те локальные переменные, которые использует выражение, вместе с указателем на скомпилированный код выражения. Этот объект должен быть интерфейсом, совместимым с вашим логическим классом, так чтобы код, использующий его, не заботился о том, имеет ли он подлинный логический или thunk-код. Всякий раз, когда кому-то нужно логическое значение, thunk выполняет код скомпилированного выражения и предоставляет полученное значение.

Если вам достаточно звонка по имени, это все, что вам нужно. Для вызова по необходимости добавлена ​​сложность из-за кэширования результата оценки.

1 голос
/ 29 марта 2012

re: Согласно Википедии "ALGOL68 использовал" процедуры "для достижения определенных пользователем операторов и процедур короткого замыкания".- Как это работает?

У Algol68-r0 (оригинальное / неизмененное определение) было два понятия, связанных с оценкой короткого замыкания.

Представьте, что кодер хочет определить оператор умножения матриц, которыйвыполнил «оценку короткого замыкания», поэтому, если левый аргумент является «нулевой» матрицей, то будет проведена дальнейшая оценка правой стороны ... Такое определение, определенное пользователем, может быть:

MODE MAT = FLEX[0,0]REAL;
OP ISZERO = (MAT a)BOOL: ¢ insert actual code here ¢ ~;

PRIO TIMESF = 7;
OP TIMESF = (MAT a, PROC MAT in b)MAT: 
  IF ISZERO a THEN a ELSE MAT b = in b; ¢ insert actual code here ¢ ~ FI;

MAT a = 0, b = 16, c = 25;
print(a TIMESF b TIMESF c) ¢ would print 0 without calculating 16*25 ¢

И наоборот, кодер хочет, чтобы левый и правый аргументы оценивались параллельно.Такие определяемые пользователем определения могут быть:

PRIO TIMESPAR = 7;
OP TIMESPAR = (MAT a, MAT b)MAT: ¢ insert actual code here ¢ ~;

Запятая говорит компилятору, что он может вычислять левую и правую руку в любом порядке или даже параллельно.(Это оставляет компилятору возможность оптимизировать оценку)

Или кодировщик может захотеть заставить оценку быть последовательной:

PRIO TIMESSEQ = 7;
OP TIMESSEQ = (MAT a; MAT b)MAT: ¢ insert actual code here ¢ ~;

В этом случае ";"называется «gomma», shofthand для «идти на запятую».

Algol68-r1 (пересмотрен в 1974 году, доступен в sourceforge для windows и linux) убрал все эти возможности, оставив кодер вручную / специально применять ""... например

Первый набор определений матриц одинаков:

MODE MAT = FLEX[0,0]REAL;
PRIO TIMESF = 7;
OP TIMESF = (MAT a, PROC MAT in b)MAT: 
  IF ISZERO a THEN a ELSE MAT b = in b; ¢ insert actual code here ¢ ~ FI;

MAT a = 0, b = 16, c = 25; ¢ 3 1x1 matrices are "widening" from REAL numbers ¢ 

Но использование отличается, обратите внимание на использование двух лямбд (MAT: b TIMES MAT:c) и (MAT: c):

print(a TIMESF MAT:b TIMESF MAT:c) ¢ would print 0 without calculating 16*25 ¢

Прозрачная депроцедура и расширение сохраняются в Algol68-r1.

1 голос
/ 27 февраля 2012

IIRC ALGOL использует параметры по имени, и именно поэтому это решение работает.

Оператор || может быть реализован как (псевдокод):

if (cond1) goto label;
if (cond2) goto label;

label:
  <body>

nomatch:
  ...

Для && может быть выполнено обратное.

...