詞法分析器-北太天元學習35
編程語言是一種將文本(源代碼)轉(zhuǎn)換為行動的程序。因為編程語言是一個與其他程序協(xié)同工作的程序,所以聽起來可能很復雜——甚至是不應該由普通人嘗試的事情——但實際上,我們普通人也可以了解編程語言是如和工作的。
?

編程語言把文本轉(zhuǎn)化為行動,可以分成幾個步驟,如下圖所示:

詞法分析(lexical analysis)是計算機科學中將字符序列轉(zhuǎn)換為單詞(Token)序列的過程。進行詞法分析的程序或者函數(shù)叫作詞法分析器(Lexical analyzer,簡稱Lexer),也叫掃描器(Scanner)。詞法分析器一般以函數(shù)的形式存在,供語法分析器調(diào)用。
我們下面給出一個用北太天元實現(xiàn)的詞法解析器供大家參考:
我會給出一個視頻,給大家簡單介紹這個詞法解析器,并且給出介紹北太天元的 global 關(guān)鍵字的使用方法,另外也會再次介紹 input 函數(shù), fprintf 函數(shù), strcmp 函數(shù) 的使用, 另外,也會介紹 switch 函數(shù), 用慣了c/c++的朋友們,可能會在 switch 里使用defualt, 但是在北太天元里, 用otherwise 代替了default?? c/c++的朋友用swtich 時還會經(jīng)常用到 case 和 break,? 但是在北太天元里每個case里相當于自動加了break,我會在視頻里把這些區(qū)別講一講。
下面我也簡單介紹一下這個詞法解析器的功能, 對于輸入一個字符串
'abc? if 1? x = 3? else? x =4? end #'
其中'#'時表示結(jié)束的字符,下面的詞法分析器會把 abc , x 分類為變量, 把數(shù)字識別出來,
把 if else end 這些關(guān)鍵詞識別出來。 在北太天元執(zhí)行時的截圖圖下:

%北太天元 實現(xiàn)一個簡單的詞法分析器
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("請輸入一個單引號字符串, 以#結(jié)束\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(關(guān)鍵字或者變量名)、數(shù)字、其它字符('>',':'等),
??? */
??? 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'))? %可能是關(guān)鍵字或者變量名
??????? 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? %將識別出來的字符和已定義的關(guān)鍵字作比較,
??????????? if(strcmp(token1, rwtab(n) ))
??????????????? syn=n; %關(guān)鍵詞的標志各不相同
??????????????? return;
?? ???? end
?? ?end?? ?
??? elseif (ch>='0'&&ch<='9')? %數(shù)字
???????? sum_=0;
???????? while((ch>='0'&&ch<='9'))
????????????? sum_=sum_*10+ch-'0';
????????????? ch=prog(p++);
?? ?? end
??????? p--;
??????? syn=11;? %數(shù)字的標志是11
??????? if(sum_>32767)? ?
?? ??? ??? ??? ?? /*
?? ??? ??? ??? ??? ? 如果數(shù)字大于32767, 則標志設(shè)置為-1,意味著出錯
?? ??? ??? ??? ??? ? 但是實際上有毛病,因為一個特別大的整數(shù)在這里會計算出
?? ??? ??? ??? ??? ? 負數(shù)
?? ??? ??? ??? ??? ? */
??????????? 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