引言
标题的这个问题,其实是一个不太正确的问题,因为对于语言而言,设计先于实现——先设计语言的语法和语义,然后写编译器去检查一个程序语法是否正确,然后根据设定好的语义将它转写成目标机器代码。从“上下文”这个视角去思考,常见情况下,语法是上下文无关的,而语义正是用来处理上下文相关的问题的,x = 1; print(x);
和 x = 2; print(x);
,同样是 print(x)
,它的上文是不一样的,所以它导致的结果也不一样.
举例 1 - =
比如:
foo = 3
foo = 4
假设对这个程序只做语法分析,那么它符合 Python 语法,也符合 Haskell 语法,但是对它做语义分析,作为一个 Python 程序,它的意思是,“先将 3
赋值给 foo
,然后将 4
赋值给 foo
”;作为一个 Haskell 程序,它不是一个合格的 Haskell 程序,因为 Haskell 语义不允许做重复的绑定,所以核心原因是,Python 的 =
的语义是赋值(assign),内存覆写,Haskell 的 =
的语义是绑定(name binding),为了保证无副作用、执行顺序无关等特性,只允许单次绑定.
举例2 - polyglot
下面这个程序改写自 polyglot(computing) wikipedia
#define a /*
echo -e "\033[34mHello, World! from echo\033[0m";// &> /dev/null;
x=5;
if (($x))
// 2> /dev/null; then
return 0;
// 2> /dev/null; fi
#define e ?>
#define b */
#include <stdio.h>
#define main() int main(void)
#define printf printf(
#define true )
#define function
function main()
{
printf "\033[31mHello, World! from main\033[0m\n"true/* 2> /dev/null | grep -v true*/;
return 0;
}
#define c /*
main
#*/
它既符合 C 语法,又符合 Bash 语法,编译/解释执行它得到的结果也是不一样的,因为两个程序的语义不同(当然 C 和 Bash 的语法也是不一样的,polyglot 编写的核心就是利用各语言之间的注释/宏/…使用的符号不同,符号(广义)的使用和布局正是语法&词法关心的事情):
