Algol:正确的语法导致编译出现问题?
Algol: correct syntax leads to problems in compilation?
下面是比较简单的代码"Evaluation of pi using the Mid-ordinate Rule on a quadrant of circle with radius 2 units."
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.
试试看 live here.
我做错了什么?如何纠正?
简答:
以下代码已解决您的特定问题...
要记住的是“;”是一个 "statement separator"... 所以所有 "compound statement" 都应该用“;”分隔每个语句.. 例如考虑:
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。 (go on 和 comma 的缩写)
例如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. Urban myth has it that the Mariner Program 发布之前发现并纠正的,有一个类似的错误导致它崩溃。
请注意,"Fake" 语句通常很有用,这用于满足 syntax/semantic 要求。 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 的情况下,有一个奇怪的情况 Yoneda 的歧义。从那以后,这种歧义一直困扰着许多编程语言,包括 Ada 和 python,甚至可能是 C...
要了解更多信息,请前往您的大学图书馆并阅读:"A History of ALGOL 68" - C. H. Lindsey - [包括对语言设计过程 "Revision by mail"、语言特性挣扎 "The Bend"和included/excluded歧义(例如米田的歧义和乱伦结合)]
在 python 中,他们试图通过将 "Separator" 设为可选并用缩进隐藏它来回避 "Separator" ……但逗号歧义仍然存在……例如。发现 syntax/semantic 错误,运行 时间错误如下...
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 也受到一点影响 "where do I put a semicolon and comma"...逻辑是“;”永远不需要跟在“}”之后,例如总是“;}”但永远不要跟在“};”之后......事实证明,有时你做需要 ";};"
然后 C 完全在作品中抛出了逗号的扳手,从不使用“,)”但有时使用“)”。
1968 年的 Algol68 确实会针对这种 class 的歧义产生错误消息。这个故事的寓意 可能 是:如果你的编译器在编译时没有发现这种歧义,那么 (只是可能) 你应该选择另一种语言。
顺便说一句:您可以找到一些示例 Algol68 程序 here...接下来是删除了尖锐边缘的代码。
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
比较代码更改,看看您是否能弄清楚效果以及它们提供的提示...:-)
或... 以下是标准数值求积程序的编码方式以供共享。注意传递函数作为参数的使用,特别是这里有一个叫做 Currying 的概念 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
下面是比较简单的代码"Evaluation of pi using the Mid-ordinate Rule on a quadrant of circle with radius 2 units."
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.
试试看 live here.
我做错了什么?如何纠正?
简答: 以下代码已解决您的特定问题...
要记住的是“;”是一个 "statement separator"... 所以所有 "compound statement" 都应该用“;”分隔每个语句.. 例如考虑:
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。 (go on 和 comma 的缩写)
例如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. Urban myth has it that the Mariner Program 发布之前发现并纠正的,有一个类似的错误导致它崩溃。
请注意,"Fake" 语句通常很有用,这用于满足 syntax/semantic 要求。 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 的情况下,有一个奇怪的情况 Yoneda 的歧义。从那以后,这种歧义一直困扰着许多编程语言,包括 Ada 和 python,甚至可能是 C...
要了解更多信息,请前往您的大学图书馆并阅读:"A History of ALGOL 68" - C. H. Lindsey - [包括对语言设计过程 "Revision by mail"、语言特性挣扎 "The Bend"和included/excluded歧义(例如米田的歧义和乱伦结合)]
在 python 中,他们试图通过将 "Separator" 设为可选并用缩进隐藏它来回避 "Separator" ……但逗号歧义仍然存在……例如。发现 syntax/semantic 错误,运行 时间错误如下...
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 也受到一点影响 "where do I put a semicolon and comma"...逻辑是“;”永远不需要跟在“}”之后,例如总是“;}”但永远不要跟在“};”之后......事实证明,有时你做需要 ";};"
然后 C 完全在作品中抛出了逗号的扳手,从不使用“,)”但有时使用“)”。
1968 年的 Algol68 确实会针对这种 class 的歧义产生错误消息。这个故事的寓意 可能 是:如果你的编译器在编译时没有发现这种歧义,那么 (只是可能) 你应该选择另一种语言。
顺便说一句:您可以找到一些示例 Algol68 程序 here...接下来是删除了尖锐边缘的代码。
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
比较代码更改,看看您是否能弄清楚效果以及它们提供的提示...:-)
或... 以下是标准数值求积程序的编码方式以供共享。注意传递函数作为参数的使用,特别是这里有一个叫做 Currying 的概念 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