杂谈向:为什么编译需要做语义分析 / 上下文(Context)与语法语义分析

引言

标题的这个问题,其实是一个不太正确的问题,因为对于语言而言,设计先于实现——先设计语言的语法和语义,然后写编译器去检查一个程序语法是否正确,然后根据设定好的语义将它转写成目标机器代码。从“上下文”这个视角去思考,常见情况下,语法是上下文无关的,而语义正是用来处理上下文相关的问题的,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 编写的核心就是利用各语言之间的注释/宏/…使用的符号不同,符号(广义)的使用和布局正是语法&词法关心的事情):

poly
Licensed under CC BY-NC-SA 4.0
Wish You a Nice Day!
Built with Hugo
Theme Stack designed by Jimmy