Алгол: правильный синтаксис приводит к проблемам при компиляции?
Вот сравнительно простой код для "Оценки числа Пи с использованием правила среднего ординаты в квадранте круга с радиусом 2 единицы".
main.alg
BEGIN
REAL x, y, sumy, pi;
INT n := lowerlimit, p := 1, lowerlimit := 10, upperlimit := 100, interval := 10;
FOR n BY interval TO upperlimit DO
sumy := 0.0;
FOR p BY 2 TO n+n-1 DO
x := p/n;
y := sqrt(4.0 - x**2);
sumy := sumy + y;
OD
pi := sumy * (2.0 / n);
print((n,pi))
OD
END
Я получаю следующие ошибки:
a68g: syntax error: 1: possibly a missing or erroneous separator nearby.
sh-4.3$ a68g main.alg
13 sumy := sumy + y;
1
a68g: warning: 1: skipped superfluous semi-symbol.
15 pi := sumy * (2.0 / n);
1
a68g: syntax error: 1: possibly a missing or erroneous separator nearby.
Попробуйте жить здесь.
Что я делаю неправильно? Как это исправить?
1 ответ
Краткий ответ: в следующем коде исправлена ваша конкретная проблема...
Следует помнить, что ";" является "разделителем операторов"... поэтому все "составные операторы" должны иметь каждый оператор, разделенный ";".. например, рассмотреть:
statement; statement; statement # is a valid program #
statement; statement statement; # is not valid #
(statement; statement; statement) # is a valid program #
(statement; statement; statement;) # is not valid #
(statement; statement; statement); # is not valid #
Мораль это... отделить все утверждения с ";" и не ставьте ";" после последнего заявления. (например, перед END, FI, DO, ")" или ESAC)
BEGIN
REAL x, y, sumy, pi;
INT n := lowerlimit, p := 1, lowerlimit := 10, upperlimit := 100, interval := 10;
FOR n BY interval TO upperlimit DO
sumy := 0.0;
FOR p BY 2 TO n+n-1 DO
x := p/n;
y := sqrt(4.0 - x**2);
sumy := sumy + y
OD;
pi := sumy * (2.0 / n);
print((n,pi))
OD
END
Интересно отметить, что вы часто можете использовать "," вместо ";", это говорит компилятору, что вам все равно, в каком порядке выполняются операторы. Это называется ГОММА. (Сокращение иди и запятая)
Например, GOMMA следует использовать с осторожностью, поскольку компилятор не обязан предупреждать вас о побочных эффектах... например (теоретически)
#!/usr/bin/a68g --script #
# -*- coding: utf-8 -*- #
INT x:=0;
(x+:=1, x+:=2); # allow the compiler the choice of threading #
PAR(x+:=10, x+:=20); # force statements into different threads #
printf(($"Answer="gl$,x))
Какой ответ? ... это может быть 33, но также может быть 21 или 12 и т. д. в зависимости от вашего компилятора.
В этом случае операция +:= настолько мала и быстра, что ответ, вероятно, будет 33.
Длинный ответ: расположение разделителей операторов на языках вызывает печаль на протяжении многих лет. Например, рассмотрим следующий код FORTRAN с пропущенной запятой:
DO 999 I=1 1000
PRINT *,I
999 CONTINUE
Эта ошибка была найдена и исправлена до запуска Project Mercury. Городской миф гласит, что в программе Mariner была похожая ошибка, приводившая к сбою.
Обратите внимание, что часто полезно иметь "поддельные" операторы, это используется для выполнения требований синтаксиса / семантики. Python в качестве различных примеров, например: "None", "NoneType" и "pass". Algol68 имеет "VOID", "SKIP" и "~"
Чтобы продемонстрировать использование SKIP (или "~").
BEGIN
REAL x, y, sumy, pi;
INT n := lowerlimit, p := 1, lowerlimit := 10, upperlimit := 100, interval := 10;
FOR n BY interval TO upperlimit DO
sumy := 0.0;
FOR p BY 2 TO n+n-1 DO
x := p/n;
y := sqrt(4.0 - x**2);
sumy := sumy + y; SKIP # insert a "fake statement after the ";" #
OD; # the ";" is still needed #
pi := sumy * (2.0 / n);
print((n,pi))
OD
END
SKIP часто используется для того, чтобы код был закомментирован:
statement1;
statement2;
SKIP COMMENT
statement3;
statement4 # eg. no ";" on the last statement #
END COMMENT
Без SKIP программа не будет компилироваться.
В случае с Algol68 есть странная ситуация с двусмысленностью Йонеды. С тех пор эта неоднозначность преследует многие языки программирования, включая Ada и python, и, возможно, даже C...
Чтобы узнать больше, зайдите в свою университетскую библиотеку и прочитайте: "История АЛГОЛА 68" - CH Lindsey - [Включает в себя откровенное отражение процесса разработки языка "Редакция по почте", языковая функция борется с "Изгибом" и включает / исключенные неясности (например, двусмысленность Йонеды и кровосмесительные союзы)]
В python они пытаются обойти "Разделитель", делая его необязательным и скрывая его с отступом... но неясность запятой осталась... например. определить синтаксическую / семантическую ошибку и ошибку времени выполнения в следующем...
print [i for i in ()]
print [i for i in (1)]
print [i for i in (1,2)]
print [i for i in (1,2,3)]
ab="ab etc etc etc"
print "first 2 only: %c,%c"%ab[0:2]
C также немного страдает от "куда я ставлю точку с запятой и запятую"... логика в том, что ";" никогда не нужно следовать за "}", например всегда ";}", но никогда "};"... Оказывается, иногда вам нужно ";};"
Затем C полностью добавляет гаечный ключ в произведениях для запятых, никогда не ",)" но иногда "),".
Algol68 1968 года выдает сообщение об ошибке для этого класса двусмысленностей. Мораль этой истории может быть следующей: если ваш компилятор не улавливает такую двусмысленность во время компиляции, тогда (возможно) вам следует выбрать другой язык.
Кстати: вы можете найти несколько примеров программ на Algol68 здесь... А затем ваш код с удаленными острыми краями.
INT lower limit = 10, upper limit = 100, interval = 10;
PROC circle = (REAL x)REAL: sqrt(4 - x**2);
FOR n FROM lower limit BY interval TO upper limit DO
REAL sum y := 0;
FOR p FROM 1 BY 2 TO 2*n DO
REAL x = p/n;
REAL y = circle(x);
sum y +:= y
OD;
REAL pi := sum y * 2 / n;
printf(($g(0)": "g(-real width,real width-2)l$,n,pi))
OD
Сравните изменения кода, чтобы увидеть, сможете ли вы выяснить эффект и какие подсказки они предоставляют...:-)
Или... вот как стандартная числовая квадратурная программа может быть закодирована для совместного использования. Обратите внимание на использование передаваемых функций в качестве аргументов, в частности, здесь есть концепция, называемая Curry. circle(2,)
... где запятая имеет значение!
INT lower limit = 10, upper limit = 100, interval = 10;
PROC circle = (REAL radius, x)REAL: sqrt(radius**2 - x**2);
PROC mid point integrate = (PROC(REAL)REAL f, REAL lwb, upb, INT num steps)REAL: (
REAL dx := (upb - lwb ) / num steps;
REAL x := lwb + dx/2;
REAL sum y := 0;
FOR p TO num steps DO
REAL y = f(x);
sum y +:= y;
x +:= dx
OD;
sum y * dx
);
FOR num steps FROM lower limit BY interval TO upper limit DO
REAL pi := mid point integrate(circle(2,),0,2,num steps);
printf(($g(0)": "g(-real width,real width-2)l$,num steps,pi))
OD