词法分析器-北太天元学习35
编程语言是一种将文本(源代码)转换为行动的程序。因为编程语言是一个与其他程序协同工作的程序,所以听起来可能很复杂——甚至是不应该由普通人尝试的事情——但实际上,我们普通人也可以了解编程语言是如和工作的。

编程语言把文本转化为行动,可以分成几个步骤,如下图所示:

词法分析(lexical analysis)是计算机科学中将字符序列转换为单词(Token)序列的过程。进行词法分析的程序或者函数叫作词法分析器(Lexical analyzer,简称Lexer),也叫扫描器(Scanner)。词法分析器一般以函数的形式存在,供语法分析器调用。
我们下面给出一个用北太天元实现的词法解析器供大家参考:
我会给出一个视频,给大家简单介绍这个词法解析器,并且给出介绍北太天元的 global 关键字的使用方法,另外也会再次介绍 input 函数, fprintf 函数, strcmp 函数 的使用, 另外,也会介绍 switch 函数, 用惯了c/c++的朋友们,可能会在 switch 里使用defualt, 但是在北太天元里, 用otherwise 代替了default c/c++的朋友用swtich 时还会经常用到 case 和 break, 但是在北太天元里每个case里相当于自动加了break,我会在视频里把这些区别讲一讲。
下面我也简单介绍一下这个词法解析器的功能, 对于输入一个字符串
'abc if 1 x = 3 else x =4 end #'
其中'#'时表示结束的字符,下面的词法分析器会把 abc , x 分类为变量, 把数字识别出来,
把 if else end 这些关键词识别出来。 在北太天元执行时的截图图下:

%北太天元 实现一个简单的词法分析器
clear all
global prog
global p
global token
global sum_
global rwtab
global syn
%prog = char(1,80); %这仅仅得到了一个2x1的char mat
prog = char(zeros(1,80)); % 这会得到一个80x1的char mat, 且初始化为''
token = char(zeros(1,8));
ch = '';
syn = 1;
p = 1;
m = 1;
n = 1;
row = 1;
sum_ = 0 ;
rwtab=["if","then","else", "switch","case","otherwise","end"];
fprintf("请输入一个单引号字符串, 以#结束\n");
while 1
ch = input("");
if(length(ch) > 0 )
prog(p:p+length(ch)-1) = ch;
p = p+length(ch);
end
if( length(ch) > 0 && strcmp(ch(end), '#') )
break;
end
end
p=1;
while 1
scaner();
switch (syn)
case 11
fprintf("(%d,%d)\n", syn, sum_);
case -1
fprintf("Error in row %d !\n",row);
case -2
row++;
otherwise %相当于c/c++的default
word = string(token(find(token != '#')));
if (~isempty(word) && word ~= "")
fprintf("(%d,%s)\n", syn, word);
end
end
if(syn == 0)
break;
end
end
function scaner()
global prog
global p
global token
global sum_
global rwtab
global syn
/*
共分为三大块,分别是token(关键字或者变量名)、数字、其它字符('>',':'等),
*/
for n=1:8
token(n)='#';
end
ch=prog(p++);
while (ch==' ')
ch=prog(p);
p++;
end
if ((ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z')) %可能是关键字或者变量名
m=1;
while((ch>='0'&&ch<='9')||(ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z'))
token(m++)=ch;
ch=prog(p++);
end
token1 = token(1:m-1);
p--;
syn=10;
for n=1:7 %将识别出来的字符和已定义的关键字作比较,
if(strcmp(token1, rwtab(n) ))
syn=n; %关键词的标志各不相同
return;
end
end
elseif (ch>='0'&&ch<='9') %数字
sum_=0;
while((ch>='0'&&ch<='9'))
sum_=sum_*10+ch-'0';
ch=prog(p++);
end
p--;
syn=11; %数字的标志是11
if(sum_>32767)
/*
如果数字大于32767, 则标志设置为-1,意味着出错
但是实际上有毛病,因为一个特别大的整数在这里会计算出
负数
*/
syn=-1;
end
return;
else
switch(ch) %其他字符
case '<'
m = 1;
token(m++) = ch;
ch = prog(p++);
if( ch == '=')
syn = 22;
token(m++) = ch;
else
syn = 23;
p --;
end
case '>'
m = 1;
token(m++) = ch;
ch = prog(p++);
if( ch == '=')
syn = 24;
token(m++) = ch;
else
syn = 20;
p --;
end
case'*'
syn=13;token(1)=ch;
case'/'
syn=14;token(1)=ch;
case'+'
syn=15;token(1)=ch;
case'-'
syn=16;token(1)=ch;
case'='
syn=25;token(1)=ch;
case';'
syn=26;token(1)=ch;
case'('
syn=27;token(1)=ch;
case')'
syn=28;token(1)=ch;
case'#'
syn=0;token(1)=ch;
case'\n'
syn=-2;
default
syn=-1;
end
end
end