work.h
1
#include
<
iostream
>
2 #include < stdlib.h >
3 #include < stdio.h >
4 #include < string .h >
5
6 /* ************STRUCT************ */
7 #ifndef keyword
8 #define keyword
9 /*
10 * 关键字结构,用于work2.cpp
11 */
12 struct KEYWORD_NODE{
13 char val[ 100 ];
14 };
15
16 /*
17 * 非终结符结构,用于work3.cpp
18 */
19 struct N_NODE{ // 非终结符
20 char val; // 值
21 int cnt; // 产生式数目
22 char ARR[ 30 ][ 30 ];
23 };
24 #endif
25
26 /* ***********FUNCTION*********** */
27 void init();
28 bool isLetter( char ch);
29 void dealSourceCode();
30 void morphologyAnalysis();
31 void dealOperatorPrecedenceGrammar();
32 using namespace std;
2 #include < stdlib.h >
3 #include < stdio.h >
4 #include < string .h >
5
6 /* ************STRUCT************ */
7 #ifndef keyword
8 #define keyword
9 /*
10 * 关键字结构,用于work2.cpp
11 */
12 struct KEYWORD_NODE{
13 char val[ 100 ];
14 };
15
16 /*
17 * 非终结符结构,用于work3.cpp
18 */
19 struct N_NODE{ // 非终结符
20 char val; // 值
21 int cnt; // 产生式数目
22 char ARR[ 30 ][ 30 ];
23 };
24 #endif
25
26 /* ***********FUNCTION*********** */
27 void init();
28 bool isLetter( char ch);
29 void dealSourceCode();
30 void morphologyAnalysis();
31 void dealOperatorPrecedenceGrammar();
32 using namespace std;
init.cpp
1
/*
**************************************************************\
2 *Author:Hu Wenbiao
3 *Created Time: Mon 15 Nov 2010 09:12:44 PM CST
4 *File Name: init.cpp
5 *Description:执行各文件所需的初始化操作
6 \************************************************************** */
7 // *========================*Head File*========================*\\
8
9 #include " work.h "
10 /* ----------------------*Global Variable*---------------------- */
11 // work2.cpp
12 extern KEYWORD_NODE KEYWORD[ 30 ];
13 // work3.cpp
14 extern bool F[ 30 ][ 30 ],L[ 30 ][ 30 ];
15 extern N_NODE N_ARRAY[ 30 ];
16 extern char T_ARRAY[ 30 ];
17 extern char PRECEDENCETABLE[ 30 ][ 30 ];
18 // *=======================*Main Program*=======================* //
19
20 /*
21 * 设置关键字,用于work2.cpp的初始化
22 */
23 void setKeyword( int pos, string str){
24 int p = 0 ;
25 while (str[p]){
26 KEYWORD[pos].val[p] = str[p];
27 p ++ ;
28 }
29 }
30
31 /*
32 * 各文件的初始化
33 */
34 void init(){
35
36 /*
37 * work2.cpp
38 */
39 memset(KEYWORD, 0 , sizeof (KEYWORD));
40 setKeyword( 1 , " const " );
41 setKeyword( 2 , " var " );
42 setKeyword( 3 , " procedure " );
43 setKeyword( 4 , " call " );
44 setKeyword( 5 , " begin " );
45 setKeyword( 6 , " end " );
46 setKeyword( 7 , " if " );
47 setKeyword( 8 , " then " );
48 setKeyword( 9 , " while " );
49 setKeyword( 10 , " do " );
50 setKeyword( 11 , " odd " );
51 setKeyword( 12 , " + " );
52 setKeyword( 13 , " - " );
53 setKeyword( 14 , " * " );
54 setKeyword( 15 , " / " );
55 setKeyword( 16 , " > " );
56 setKeyword( 17 , " >= " );
57 setKeyword( 18 , " < " );
58 setKeyword( 19 , " <= " );
59 setKeyword( 20 , " = " );
60 setKeyword( 21 , " <> " );
61 setKeyword( 22 , " . " );
62 setKeyword( 23 , " ( " );
63 setKeyword( 24 , " ) " );
64 setKeyword( 25 , " , " );
65 setKeyword( 26 , " ; " );
66 setKeyword( 27 , " := " );
67
68 /*
69 * work3.cpp
70 */
71 memset(N_ARRAY, 0 , sizeof (N_ARRAY));
72 memset(T_ARRAY, 0 , sizeof (T_ARRAY));
73 memset(F, 0 , sizeof (F));
74 memset(L, 0 , sizeof (F));
75 memset(PRECEDENCETABLE, 0 , sizeof (PRECEDENCETABLE));
76 }
2 *Author:Hu Wenbiao
3 *Created Time: Mon 15 Nov 2010 09:12:44 PM CST
4 *File Name: init.cpp
5 *Description:执行各文件所需的初始化操作
6 \************************************************************** */
7 // *========================*Head File*========================*\\
8
9 #include " work.h "
10 /* ----------------------*Global Variable*---------------------- */
11 // work2.cpp
12 extern KEYWORD_NODE KEYWORD[ 30 ];
13 // work3.cpp
14 extern bool F[ 30 ][ 30 ],L[ 30 ][ 30 ];
15 extern N_NODE N_ARRAY[ 30 ];
16 extern char T_ARRAY[ 30 ];
17 extern char PRECEDENCETABLE[ 30 ][ 30 ];
18 // *=======================*Main Program*=======================* //
19
20 /*
21 * 设置关键字,用于work2.cpp的初始化
22 */
23 void setKeyword( int pos, string str){
24 int p = 0 ;
25 while (str[p]){
26 KEYWORD[pos].val[p] = str[p];
27 p ++ ;
28 }
29 }
30
31 /*
32 * 各文件的初始化
33 */
34 void init(){
35
36 /*
37 * work2.cpp
38 */
39 memset(KEYWORD, 0 , sizeof (KEYWORD));
40 setKeyword( 1 , " const " );
41 setKeyword( 2 , " var " );
42 setKeyword( 3 , " procedure " );
43 setKeyword( 4 , " call " );
44 setKeyword( 5 , " begin " );
45 setKeyword( 6 , " end " );
46 setKeyword( 7 , " if " );
47 setKeyword( 8 , " then " );
48 setKeyword( 9 , " while " );
49 setKeyword( 10 , " do " );
50 setKeyword( 11 , " odd " );
51 setKeyword( 12 , " + " );
52 setKeyword( 13 , " - " );
53 setKeyword( 14 , " * " );
54 setKeyword( 15 , " / " );
55 setKeyword( 16 , " > " );
56 setKeyword( 17 , " >= " );
57 setKeyword( 18 , " < " );
58 setKeyword( 19 , " <= " );
59 setKeyword( 20 , " = " );
60 setKeyword( 21 , " <> " );
61 setKeyword( 22 , " . " );
62 setKeyword( 23 , " ( " );
63 setKeyword( 24 , " ) " );
64 setKeyword( 25 , " , " );
65 setKeyword( 26 , " ; " );
66 setKeyword( 27 , " := " );
67
68 /*
69 * work3.cpp
70 */
71 memset(N_ARRAY, 0 , sizeof (N_ARRAY));
72 memset(T_ARRAY, 0 , sizeof (T_ARRAY));
73 memset(F, 0 , sizeof (F));
74 memset(L, 0 , sizeof (F));
75 memset(PRECEDENCETABLE, 0 , sizeof (PRECEDENCETABLE));
76 }
work1.cpp
1
/*
**************************************************************\ * Author: Hu Wenbiao
2 * Created Time: Wed 06 Oct 2010 09:29:56 AM CST
3 * File Name: work1.cpp
4 * Description: 处理源代码格式,将多余空格去掉,换行,跳格改成空格
5 * 去掉注释。
6 \************************************************************** */
7 // *========================*Head File*========================*\\
8
9 #include " work.h "
10 /* ----------------------*Global Variable*---------------------- */
11
12 // *=======================*Main Program*=======================* //
13
14 /*
15 * 处理空格和注释
16 */
17 void dealSourceCode(){
18 bool space = false ,multiply = false ,slash = false ,quote = false ;
19 char ch;
20 int slash_multiply = 0 ;
21 while (scanf( " %c " , & ch) != EOF){
22
23 if (ch == ' \\ ' ){ // 转义符
24 printf( " \\ " );
25 scanf( " %c " , & ch);
26 printf( " %c " ,ch);
27 continue ;
28 }
29
30 if (quote){ // 有引号
31 // 有printf("\"")这种情况
32 // 有printf("\\")这种情况
33 // 有printf("")这种情况
34
35 if (ch == ' \" ' ){ // 第三种情况
36 printf( " \ "" );
37 quote = false ;
38 continue ;
39 }
40
41 /* 处理前两种情况 */
42 char buf[ 10000 ];
43 int p = 0 ;
44 buf[p ++ ] = ch;
45 while (scanf( " %c " , & buf[p]) != EOF && (buf[p] != ' \" ' || (buf[p - 1 ] == ' \\ ' && (p == 1 || buf[p - 2 ] != ' \\ ' ))))p ++ ;
46 buf[p + 1 ] = ' \0 ' ;
47 printf( " %s " ,buf);
48 quote = false ;
49 continue ;
50 }
51
52 if (ch == ' ' || ch == ' \n ' || ch == ' \t ' ){ // 空格处理
53 if ( ! space){
54 printf( " " );
55 space = true ;
56 }
57 while (scanf( " %c " , & ch) != EOF && (ch == ' ' || ch == ' \n ' || ch == ' \t ' ));
58 }
59
60 if (ch == ' / ' ){ // 有可能是注释,注释处理
61 scanf( " %c " , & ch);
62
63 if (ch == ' / ' ){ // 单行注释
64 while (scanf( " %c " , & ch) != EOF && ch != ' \n ' );
65 }
66 else if (ch == ' * ' ){ // 多行注释
67 slash_multiply = 1 ;
68 slash = multiply = false ;
69 while (slash_multiply){
70 if (scanf( " %c " , & ch) == EOF) break ; // 输入源文件语法错误
71 if (ch == ' / ' ){
72 if (multiply){
73 slash_multiply -- ;
74 multiply = slash = false ;
75 }
76 else
77 slash = true ;
78 }
79 else if (ch == ' * ' ){
80 if (slash){
81 slash_multiply ++ ;
82 multiply = slash = false ;
83 }
84 else
85 multiply = true ;
86 }
87 }
88 }
89 else { // 不是注释
90 printf( " / " );
91 if (ch == ' ' || ch == ' \n ' || ch == ' \t ' )
92 space = true ;
93 printf( " %c " ,ch);
94 }
95 }
96 else if (ch == ' \" ' ){ // 发现第一个引号"\""
97 printf( " \ "" );
98 quote = true ;
99 }
100 else { // 普通字符
101 printf( " %c " ,ch);
102 space = false ;
103 }
104 }
105 }
106 /*
107 int main(){
108 freopen("input.txt","r",stdin);
109 freopen("output.txt","w",stdout);
110 dealSourceCode();
111 return 0;
112 }
113 */
2 * Created Time: Wed 06 Oct 2010 09:29:56 AM CST
3 * File Name: work1.cpp
4 * Description: 处理源代码格式,将多余空格去掉,换行,跳格改成空格
5 * 去掉注释。
6 \************************************************************** */
7 // *========================*Head File*========================*\\
8
9 #include " work.h "
10 /* ----------------------*Global Variable*---------------------- */
11
12 // *=======================*Main Program*=======================* //
13
14 /*
15 * 处理空格和注释
16 */
17 void dealSourceCode(){
18 bool space = false ,multiply = false ,slash = false ,quote = false ;
19 char ch;
20 int slash_multiply = 0 ;
21 while (scanf( " %c " , & ch) != EOF){
22
23 if (ch == ' \\ ' ){ // 转义符
24 printf( " \\ " );
25 scanf( " %c " , & ch);
26 printf( " %c " ,ch);
27 continue ;
28 }
29
30 if (quote){ // 有引号
31 // 有printf("\"")这种情况
32 // 有printf("\\")这种情况
33 // 有printf("")这种情况
34
35 if (ch == ' \" ' ){ // 第三种情况
36 printf( " \ "" );
37 quote = false ;
38 continue ;
39 }
40
41 /* 处理前两种情况 */
42 char buf[ 10000 ];
43 int p = 0 ;
44 buf[p ++ ] = ch;
45 while (scanf( " %c " , & buf[p]) != EOF && (buf[p] != ' \" ' || (buf[p - 1 ] == ' \\ ' && (p == 1 || buf[p - 2 ] != ' \\ ' ))))p ++ ;
46 buf[p + 1 ] = ' \0 ' ;
47 printf( " %s " ,buf);
48 quote = false ;
49 continue ;
50 }
51
52 if (ch == ' ' || ch == ' \n ' || ch == ' \t ' ){ // 空格处理
53 if ( ! space){
54 printf( " " );
55 space = true ;
56 }
57 while (scanf( " %c " , & ch) != EOF && (ch == ' ' || ch == ' \n ' || ch == ' \t ' ));
58 }
59
60 if (ch == ' / ' ){ // 有可能是注释,注释处理
61 scanf( " %c " , & ch);
62
63 if (ch == ' / ' ){ // 单行注释
64 while (scanf( " %c " , & ch) != EOF && ch != ' \n ' );
65 }
66 else if (ch == ' * ' ){ // 多行注释
67 slash_multiply = 1 ;
68 slash = multiply = false ;
69 while (slash_multiply){
70 if (scanf( " %c " , & ch) == EOF) break ; // 输入源文件语法错误
71 if (ch == ' / ' ){
72 if (multiply){
73 slash_multiply -- ;
74 multiply = slash = false ;
75 }
76 else
77 slash = true ;
78 }
79 else if (ch == ' * ' ){
80 if (slash){
81 slash_multiply ++ ;
82 multiply = slash = false ;
83 }
84 else
85 multiply = true ;
86 }
87 }
88 }
89 else { // 不是注释
90 printf( " / " );
91 if (ch == ' ' || ch == ' \n ' || ch == ' \t ' )
92 space = true ;
93 printf( " %c " ,ch);
94 }
95 }
96 else if (ch == ' \" ' ){ // 发现第一个引号"\""
97 printf( " \ "" );
98 quote = true ;
99 }
100 else { // 普通字符
101 printf( " %c " ,ch);
102 space = false ;
103 }
104 }
105 }
106 /*
107 int main(){
108 freopen("input.txt","r",stdin);
109 freopen("output.txt","w",stdout);
110 dealSourceCode();
111 return 0;
112 }
113 */
work2.cpp
/*
**************************************************************\
*Author:Hu Wenbiao
*Created Time: Mon 15 Nov 2010 07:09:54 PM CST
*File Name: work2.cpp
*Description:词法分析器
\************************************************************** */
// *========================*Head File*========================*\\
#include " work.h "
/* ----------------------*Global Variable*---------------------- */
KEYWORD_NODE KEYWORD[ 30 ];
// *=======================*Main Program*=======================* //
bool isLetter( char ch){ // 判断是否是字母
return (ch >= ' a ' && ch <= ' z ' ) || (ch >= ' A ' && ch <= ' Z ' ) || (ch >= ' 0 ' && ch <= ' 9 ' );
}
bool isNumber( char ch){ // 判断是否是数字
return ch >= ' 0 ' && ch <= ' 9 ' ;
}
/*
*判断是否是关键字,是则返回编码,否则返回28(标识符)
*/
int getKeywordId( char * str, int s, int t){
int i,p;
for (i = 0 ;i < 12 ;i ++ ){
p = 0 ;
while (KEYWORD[i].val[p] && s + p <= t &&
KEYWORD[i].val[p] == str[s + p]){
p ++ ;
}
if (KEYWORD[i].val[p] == ' \0 ' && s + p > t)
return i;
}
return 28 ; // id
}
/*
*判断是否是分隔符或操作符,是则返回编码,否则返回0(Error)
*/
int getSepOrOprId( char * str, int s, int t){
int i,p;
for (i = 12 ;i < 28 ;i ++ ){
p = 0 ;
while (KEYWORD[i].val[p] && s <= t &&
KEYWORD[i].val[p] == str[s]){
p ++ ,s ++ ;
}
if (KEYWORD[i].val[p] == ' \0 ' && s > t)
return i;
}
return 0 ; // Error
}
/*
* 按要求的格式输出
*/
void printOut( int id, char * str, int s, int t){
printf( " %d: " ,id);
for (;s <= t;s ++ )
printf( " %c " ,str[s]);
printf( " \n " );
}
/*
* 是否是分隔符或操作符组成元素
*/
bool isSepOrOpr( char ch){
return ch == ' + ' || ch == ' - ' || ch == ' * ' || ch == ' / ' || ch == ' > ' || ch == ' < ' || ch == ' = '
|| ch == ' . ' || ch == ' ( ' || ch == ' ) ' || ch == ' , ' || ch == ' ; ' || ch == ' : ' ;
}
/*
* 对字符串str进行分析
*/
void dealMorphology( char * str){
int p = 0 ,s,t;
while (str[p]){
s = t = p;
if (isNumber(str[p])){ // 整型
while (str[p] && isNumber(str[p])) p ++ ;
t = p - 1 ;
if (isLetter(str[p])){ // 整型中有字母,错误
printOut( 0 ,str,s,t);
}
else { // 整型
printOut( 29 ,str,s,t);
}
}
else if (isLetter(str[p])){ // 标识符
while (str[p] && (isLetter(str[p]) || isNumber(str[p]))) p ++ ;
t = p - 1 ;
printOut(getKeywordId(str,s,t),str,s,t);
}
else if (isSepOrOpr(str[p])){ // 分隔符或操作符
while (str[p] && isSepOrOpr(str[p])) p ++ ;
t = p - 1 ;
printOut(getSepOrOprId(str,s,t),str,s,t);
}
else if (s == t && str[s] == ' \n ' ){
p ++ ;
continue ;
}
else {
printf( " ERROR:\n " );
p ++ ;
}
}
}
/*
* 将dealSourceCode()处理后代码按空格进行分成若干字符串进行分别处理
*/
void morphologyAnalysis(){
char str[ 1000 ]; int p; bool flag = true ;
while (flag){
p = 0 ;
while ((flag = (scanf( " %c " , & str[p]) != EOF)) && str[p] != ' ' ) p ++ ;
str[p] = 0 ;
dealMorphology(str);
}
}
*Author:Hu Wenbiao
*Created Time: Mon 15 Nov 2010 07:09:54 PM CST
*File Name: work2.cpp
*Description:词法分析器
\************************************************************** */
// *========================*Head File*========================*\\
#include " work.h "
/* ----------------------*Global Variable*---------------------- */
KEYWORD_NODE KEYWORD[ 30 ];
// *=======================*Main Program*=======================* //
bool isLetter( char ch){ // 判断是否是字母
return (ch >= ' a ' && ch <= ' z ' ) || (ch >= ' A ' && ch <= ' Z ' ) || (ch >= ' 0 ' && ch <= ' 9 ' );
}
bool isNumber( char ch){ // 判断是否是数字
return ch >= ' 0 ' && ch <= ' 9 ' ;
}
/*
*判断是否是关键字,是则返回编码,否则返回28(标识符)
*/
int getKeywordId( char * str, int s, int t){
int i,p;
for (i = 0 ;i < 12 ;i ++ ){
p = 0 ;
while (KEYWORD[i].val[p] && s + p <= t &&
KEYWORD[i].val[p] == str[s + p]){
p ++ ;
}
if (KEYWORD[i].val[p] == ' \0 ' && s + p > t)
return i;
}
return 28 ; // id
}
/*
*判断是否是分隔符或操作符,是则返回编码,否则返回0(Error)
*/
int getSepOrOprId( char * str, int s, int t){
int i,p;
for (i = 12 ;i < 28 ;i ++ ){
p = 0 ;
while (KEYWORD[i].val[p] && s <= t &&
KEYWORD[i].val[p] == str[s]){
p ++ ,s ++ ;
}
if (KEYWORD[i].val[p] == ' \0 ' && s > t)
return i;
}
return 0 ; // Error
}
/*
* 按要求的格式输出
*/
void printOut( int id, char * str, int s, int t){
printf( " %d: " ,id);
for (;s <= t;s ++ )
printf( " %c " ,str[s]);
printf( " \n " );
}
/*
* 是否是分隔符或操作符组成元素
*/
bool isSepOrOpr( char ch){
return ch == ' + ' || ch == ' - ' || ch == ' * ' || ch == ' / ' || ch == ' > ' || ch == ' < ' || ch == ' = '
|| ch == ' . ' || ch == ' ( ' || ch == ' ) ' || ch == ' , ' || ch == ' ; ' || ch == ' : ' ;
}
/*
* 对字符串str进行分析
*/
void dealMorphology( char * str){
int p = 0 ,s,t;
while (str[p]){
s = t = p;
if (isNumber(str[p])){ // 整型
while (str[p] && isNumber(str[p])) p ++ ;
t = p - 1 ;
if (isLetter(str[p])){ // 整型中有字母,错误
printOut( 0 ,str,s,t);
}
else { // 整型
printOut( 29 ,str,s,t);
}
}
else if (isLetter(str[p])){ // 标识符
while (str[p] && (isLetter(str[p]) || isNumber(str[p]))) p ++ ;
t = p - 1 ;
printOut(getKeywordId(str,s,t),str,s,t);
}
else if (isSepOrOpr(str[p])){ // 分隔符或操作符
while (str[p] && isSepOrOpr(str[p])) p ++ ;
t = p - 1 ;
printOut(getSepOrOprId(str,s,t),str,s,t);
}
else if (s == t && str[s] == ' \n ' ){
p ++ ;
continue ;
}
else {
printf( " ERROR:\n " );
p ++ ;
}
}
}
/*
* 将dealSourceCode()处理后代码按空格进行分成若干字符串进行分别处理
*/
void morphologyAnalysis(){
char str[ 1000 ]; int p; bool flag = true ;
while (flag){
p = 0 ;
while ((flag = (scanf( " %c " , & str[p]) != EOF)) && str[p] != ' ' ) p ++ ;
str[p] = 0 ;
dealMorphology(str);
}
}
work3.cpp
1
/*
**************************************************************\
2 *Author:Hu Wenbiao
3 *Created Time: Tue 16 Nov 2010 05:11:20 PM CST
4 *File Name: work3.cpp
5 *Description:算符优先文法
6 * 1.非终结符和终结符的编号(id)都是它们在数组中的下标
7 * 2.算法只能处理单字符的非终结符和终结符(大写字母为非终结符,
8 * 其他为终结符)
9 * 3.处理的表达式必须含有:=且其左边不能含有运算符,否则会被作为
10 * 标识符的一部分处理
11 * 4.表达式的标识符可以是字符串如:aa=bb+cc+dd*eef
12 * 5.处理表达式时先将标识符转化为i(因为文法中只用i表示标识符),
13 * 标识符的名称在NAME中记录,另外产生的中间标识符(如T1、E2)
14 * 的名称也在NAME中记录,名称的id为其下标,NAME[0]记录等号“:=”
15 * 左边的那个标识符,对于其他的标识符若id为0表示出错
16 \************************************************************** */
17 // *========================*Head File*========================*\\
18
19 #include < stack >
20 #include " work.h "
21
22 /* ----------------------*Global Variable*---------------------- */
23
24 N_NODE N_ARRAY[ 30 ]; // 非终端符数组(下标从1开始)
25 char T_ARRAY[ 30 ]; // 终端符数组(下标从1开始)
26 bool F[ 30 ][ 30 ],L[ 30 ][ 30 ]; // F[i][j]表示id为j的终结符是否属于
27 // id为i的非终结符的FIRSTVT,L相同。
28 stack < pair < int , int > > S; // 用于求FIRSTVT和LASTVT
29 char PRECEDENCETABLE[ 30 ][ 30 ]; // 算符优先关系表
30 char NAME[ 100 ][ 10 ]; // 用来存放标识符名称,NAME[i]表示id为i的标识符
31 int name_foot[ 100 ]; // 分配中间标识符的下标,如T1中的1
32 // *=======================*Main Program*=======================* //
33
34 int getTnodeId( char ch){ // 返回终端符编码(下标),不存在返回0
35 int p = 1 ;
36 while (T_ARRAY[p] && T_ARRAY[p] != ch) p ++ ;
37 if (T_ARRAY[p])
38 return p;
39 else
40 return 0 ;
41 }
42
43 int getNnodeId( char ch){ // 返回非终端符编码(下标),不存在返回0
44 int pos = 1 ;
45 while (N_ARRAY[pos].val && N_ARRAY[pos].val != ch) pos ++ ;
46 if (N_ARRAY[pos].val)
47 return pos;
48 else
49 return 0 ;
50 }
51
52 int getNameId( char * str, int s, int t){ // 给str[s]~str[t]分配位置,并返回id
53 int ptr = 0 ;
54 while (NAME[ptr][ 0 ])ptr ++ ;
55
56 for ( int i = 0 ;s + i <= t;i ++ )
57 NAME[ptr][i] = str[s + i];
58
59 return ptr;
60 }
61
62 int getNameId( char ch){ // 同上,重载
63 name_foot[ch] ++ ;
64 int ptr = 0 ;
65 while (NAME[ptr][ 0 ])ptr ++ ;
66
67 NAME[ptr][ 0 ] = ch;
68 NAME[ptr][ 1 ] = char (name_foot[ch] + ' 0 ' );
69
70 return ptr;
71 }
72
73 void insertN_ARRAY( char val, char * str, int s, int t){ // 增加非终结符
74 int pos = 1 ;
75 while (N_ARRAY[pos].val && N_ARRAY[pos].val != val) pos ++ ;
76 N_ARRAY[pos].val = val;
77 int cnt = N_ARRAY[pos].cnt,p = 0 ;
78 for (;s <= t;p ++ ,s ++ ){
79 N_ARRAY[pos].ARR[cnt][p] = str[s];
80 }
81 N_ARRAY[pos].cnt ++ ;
82 }
83
84 void insertT_ARRAY( char ch){ // 增加终结符
85 int p = 1 ;
86 while (T_ARRAY[p]) p ++ ;
87 T_ARRAY[p] = ch;
88 }
89
90 bool isNnode( char ch){ // 判断是否是非终结符
91 return ch >= ' A ' && ch <= ' Z ' ;
92 }
93
94 /*
95 * 求解所有非终结符的FIRSTVT
96 */
97
98 void getFIRSTVT(){
99 pair < int , int > cur; // cur.first是非终结符的id,cur.second是终结符的id
100 int nr_Nnode = 1 ;
101 while (N_ARRAY[nr_Nnode].val) nr_Nnode ++ ; // 其实nr_Nnode=(nr of Nnode)+1
102 for ( int i = 1 ;i < nr_Nnode;i ++ ){ // 每个非终结符
103 for ( int j = 0 ;j < N_ARRAY[i].cnt;j ++ ){ // 每个产生式
104 if ( ! isNnode(N_ARRAY[i].ARR[j][ 0 ])){ // N_ARRAY[i].ARR[j][0]是终结符
105 int id_Tnode = getTnodeId(N_ARRAY[i].ARR[j][ 0 ]);
106 if (F[i][id_Tnode]) continue ;
107 F[i][id_Tnode] = true ;
108 S.push(pair < int , int > (i,id_Tnode));
109 }
110 // N_ARRAY[i].ARR[j][1]是终结符
111 else if (N_ARRAY[i].ARR[j][ 1 ] && ! isNnode(N_ARRAY[i].ARR[j][ 1 ])){
112 int id_Tnode = getTnodeId(N_ARRAY[i].ARR[j][ 1 ]);
113 if (F[i][id_Tnode]) continue ;
114 F[i][id_Tnode] = true ;
115 S.push(pair < int , int > (i,id_Tnode));
116 }
117 }
118 }
119 while ( ! S.empty()){
120 cur = S.top(),S.pop();
121 char curNnodeVal = N_ARRAY[cur.first].val;
122
123 for ( int i = 1 ;i < nr_Nnode;i ++ ){
124 if (F[i][cur.second]) continue ; // cur.second已经属于FIRSTVT(i)
125 for ( int j = 0 ;j < N_ARRAY[i].cnt;j ++ ){ // 查找哪个产生式右边以curNnodeVal为首
126 if (N_ARRAY[i].ARR[j][ 0 ] == curNnodeVal){
127 F[i][cur.second] = true ;
128 S.push(pair < int , int > (i,cur.second));
129 break ;
130 }
131 }
132 }
133 }
134 /* 输出FIRSTVT */
135 for ( int i = 1 ;i < nr_Nnode;i ++ ){
136 for ( int j = 1 ;j < 30 ;j ++ ){
137 if (F[i][j]){
138 printf( " FIRSTVT(%c): { " ,N_ARRAY[i].val);
139 while (j < 30 ){
140 if (F[i][j])
141 printf( " %c " ,T_ARRAY[j]);
142 j ++ ;
143 }
144 printf( " }\n " );
145 }
146 }
147 }
148 printf( " \n " );
149 /**/
150 }
151
152 /*
153 * 求解所有非终结符的LASTVT
154 */
155
156 void getLASTVT(){
157 pair < int , int > cur;
158 int nr_Nnode = 1 ;
159 while (N_ARRAY[nr_Nnode].val) nr_Nnode ++ ;
160 for ( int i = 1 ;i < nr_Nnode;i ++ ){
161 for ( int j = 0 ;j < N_ARRAY[i].cnt;j ++ ){
162 int ptr = 0 ;
163 while (N_ARRAY[i].ARR[j][ptr]) ptr ++ ;
164 ptr -- ;
165 if ( ! isNnode(N_ARRAY[i].ARR[j][ptr])){
166 int id_Tnode = getTnodeId(N_ARRAY[i].ARR[j][ptr]);
167 if (L[i][id_Tnode]) continue ;
168 L[i][id_Tnode] = true ;
169 S.push(pair < int , int > (i,id_Tnode));
170 }
171 else if (ptr > 0 &&! isNnode(N_ARRAY[i].ARR[j][ptr - 1 ])){
172 int id_Tnode = getTnodeId(N_ARRAY[i].ARR[j][ptr - 1 ]);
173 if (L[i][id_Tnode]) continue ;
174 L[i][id_Tnode] = true ;
175 S.push(pair < int , int > (i,id_Tnode));
176 }
177 }
178 }
179 while ( ! S.empty()){
180 cur = S.top(),S.pop();
181 char curNnodeVal = N_ARRAY[cur.first].val;
182
183 for ( int i = 1 ;i < nr_Nnode;i ++ ){
184 for ( int j = 0 ;j < N_ARRAY[i].cnt;j ++ ){
185 int ptr = 0 ;
186 while (N_ARRAY[i].ARR[j][ptr]) ptr ++ ;
187 ptr -- ;
188 if (N_ARRAY[i].ARR[j][ptr] == curNnodeVal &&
189 ! L[i][cur.second]){
190 L[i][cur.second] = true ;
191 S.push(pair < int , int > (i,cur.second));
192 break ;
193 }
194 }
195 }
196 }
197 /* 输出LASTVT */
198 for ( int i = 1 ;i < nr_Nnode;i ++ ){
199 for ( int j = 1 ;j < 30 ;j ++ ){
200 if (L[i][j]){
201 printf( " LASTVT(%c): { " ,N_ARRAY[i].val);
202 while (j < 30 ){
203 if (L[i][j])
204 printf( " %c " ,T_ARRAY[j]);
205 j ++ ;
206 }
207 printf( " }\n " );
208 }
209 }
210 }
211 printf( " \n " );
212 /**/
213 }
214
215 /*
216 * 求算符优先表
217 */
218
219 void getPrecedenceTable(){
220 int nr_Nnode = 1 ,nr_Tnode = 1 ;
221 while (N_ARRAY[nr_Nnode].val) nr_Nnode ++ ;
222 while (T_ARRAY[nr_Tnode]) nr_Tnode ++ ;
223
224 /* *关于#的比较* */
225 int id_sharp = getTnodeId( ' # ' );
226 for ( int j = 1 ;j < nr_Tnode;j ++ ){
227 if (F[ 1 ][j]){
228 PRECEDENCETABLE[id_sharp][j] = ' < ' ;
229 }
230 if (L[ 1 ][j]){
231 PRECEDENCETABLE[j][id_sharp] = ' > ' ;
232 }
233 }
234
235 /* ************* */
236
237 for ( int i = 1 ;i < nr_Nnode;i ++ ){ // 每个非终结符
238 for ( int j = 0 ;j < N_ARRAY[i].cnt;j ++ ){ // 每个产生式
239 int tail = 0 ;
240 while (N_ARRAY[i].ARR[j][tail]) tail ++ ;
241 tail -- ; // 最后一位(非零)
242 for ( int p = 0 ;p < tail;p ++ ){
243 // tt
244 if ( ! isNnode(N_ARRAY[i].ARR[j][p]) &&
245 ! isNnode(N_ARRAY[i].ARR[j][p + 1 ])){
246 int id1 = getTnodeId(N_ARRAY[i].ARR[j][p]);
247 int id2 = getTnodeId(N_ARRAY[i].ARR[j][p + 1 ]);
248 if (PRECEDENCETABLE[id1][id2]){
249 printf( " ERROR:不是算符优先文法! " );
250 exit(EXIT_FAILURE);
251 }
252 PRECEDENCETABLE[id1][id2] = ' = ' ;
253 }
254 // tNt
255 if (p <= tail - 2 &&! isNnode(N_ARRAY[i].ARR[j][p]) &&
256 isNnode(N_ARRAY[i].ARR[j][p + 1 ]) &&
257 ! isNnode(N_ARRAY[i].ARR[j][p + 2 ])){
258 int id1 = getTnodeId(N_ARRAY[i].ARR[j][p]);
259 int id2 = getTnodeId(N_ARRAY[i].ARR[j][p + 2 ]);
260 if (PRECEDENCETABLE[id1][id2]){
261 printf( " ERROR:不是算符优先文法! " );
262 exit(EXIT_FAILURE);
263 }
264 PRECEDENCETABLE[id1][id2] = ' = ' ;
265 }
266 // tN
267 if ( ! isNnode(N_ARRAY[i].ARR[j][p]) &&
268 isNnode(N_ARRAY[i].ARR[j][p + 1 ])){
269 int id1 = getTnodeId(N_ARRAY[i].ARR[j][p]);
270 int id_Nnode = getNnodeId(N_ARRAY[i].ARR[j][p + 1 ]);
271 int id2 = 1 ;
272 while (T_ARRAY[id2]){
273 if (F[id_Nnode][id2]){
274 if (PRECEDENCETABLE[id1][id2]){
275 printf( " ERROR:不是算符优先文法! " );
276 exit(EXIT_FAILURE);
277 }
278 PRECEDENCETABLE[id1][id2] = ' < ' ;
279 }
280 id2 ++ ;
281 }
282 }
283 // Nt
284 if (isNnode(N_ARRAY[i].ARR[j][p]) &&
285 ! isNnode(N_ARRAY[i].ARR[j][p + 1 ])){
286 int id_Nnode = getNnodeId(N_ARRAY[i].ARR[j][p]);
287 int id2 = getTnodeId(N_ARRAY[i].ARR[j][p + 1 ]);
288 int id1 = 1 ;
289 while (T_ARRAY[id1]){
290 if (L[id_Nnode][id1]){
291 if (PRECEDENCETABLE[id1][id2]){
292 printf( " ERROR:不是算符优先方法! " );
293 exit(EXIT_FAILURE);
294 }
295 PRECEDENCETABLE[id1][id2] = ' > ' ;
296 }
297 id1 ++ ;
298 }
299 }
300 }
301 }
302 }
303 // 输出优先表 // //
304 cout << " " ;
305 for ( int i = 1 ;i < nr_Tnode;i ++ ){
306 cout << T_ARRAY[i] << " " ;
307 }
308 cout << endl;
309 for ( int i = 1 ;i < nr_Tnode;i ++ ){
310 cout << T_ARRAY[i] << " " ;
311 for ( int j = 1 ;j < nr_Tnode;j ++ ){
312 if (PRECEDENCETABLE[i][j])
313 cout << PRECEDENCETABLE[i][j] << " " ;
314 else
315 cout << " " ;
316 }
317 cout << endl;
318 }
319 cout << endl;
320 / /
321 }
322
323 /*
324 * 比较ARR[s]~ARR[t]中的id和str中的符号是否匹配
325 * 其中非终结符的id是取负值的,比较时也不比较非
326 * 终结符是否相同,只要求终结符相同,非终结符相
327 * 对应就返回true
328 */
329
330 bool cmpIdNodeVal(pair < int , int >* ARR, int s, int t, char * str){
331 int ptr = 0 ,id;
332 while (s <= t && str[ptr]){
333 if (isNnode(str[ptr])){ // 非终结符
334 if (ARR[s].first > 0 )
335 return false ;
336 }
337 else if (ARR[s].first != getTnodeId(str[ptr]))
338 return false ;
339 ptr ++ ;
340 s ++ ;
341 }
342 if (s <= t || str[ptr])
343 return false ;
344 return true ;
345 }
346
347 /*
348 * 将STACK[s]~STACK[t]归约,返回归约后的非终结符的值,
349 * 分配并由name返回非终结符的名称id
350 */
351
352 char reduction(pair < int , int >* STACK, int s, int t, int & name){
353 int i = 1 ;
354 while (N_ARRAY[i].val){
355 for ( int j = 0 ;j < N_ARRAY[i].cnt;j ++ ){
356 if (cmpIdNodeVal(STACK,s,t,N_ARRAY[i].ARR[j])){ // 查找成功
357
358
359 /// 输出 ///
360
361 if (s == t && STACK[s].first > 0 ){ // 1
362 name = STACK[s].second;
363 }
364
365 if (s + 1 == t){ // 2
366 name = getNameId(N_ARRAY[i].val);
367 if (STACK[s].first > 0 ){
368 printf( " (%c,_,%s,%s)\n " ,
369 T_ARRAY[STACK[s].first],NAME[STACK[t].second],NAME[name]);
370 }
371 else {
372 printf( " (%c,%s,_,%s)\n " ,
373 T_ARRAY[STACK[t].first],NAME[STACK[s].second],NAME[name]);
374 }
375 }
376 if (s + 2 == t){ // 3
377 if (STACK[s].first > 0 && STACK[t].first > 0 ){ // (T)这种情况
378 name = STACK[s + 1 ].second;
379 }
380 else {
381 name = getNameId(N_ARRAY[i].val);
382 printf( " (%c,%s,%s,%s)\n " ,T_ARRAY[STACK[s + 1 ].first],
383 NAME[STACK[s].second],NAME[STACK[t].second],NAME[name]);
384 }
385 }
386
387 / /
388
389 return N_ARRAY[i].val;
390 }
391 }
392 i ++ ;
393 }
394 return 0 ;
395 }
396
397 /*
398 * 核心函数,处理传入的单句表达式,要求表达式必须为
399 * abc:=x*y+zuv 的形式,即必须有:=号且其左边不能有运
400 * 算符,否则会被当作标识符的一部分处理
401 */
402
403 void operatorPrecedenceParser( char * str0){
404 /// 将空格去掉 ///
405 int s = 0 ,t = 0 ,p;
406 while (str0[t]){
407 if (str0[t] != ' ' ){
408 str0[s] = str0[t];
409 s ++ ;
410 }
411 t ++ ;
412 }
413 str0[s] = 0 ;
414
415 /// 将str0转换成str,由文法符号表示 ///
416 char str[ 1000 ];
417 int str_name[ 1000 ]; // str_name[i]是str[i]的名称,当str[i]为操作符时无意义
418
419 memset(NAME, 0 , sizeof (NAME));
420 memset(name_foot, 0 , sizeof (name_foot));
421
422 s = 0 ;
423 while (str0[s] && str0[s] != ' : ' )s ++ ;
424 if (str0[s] == 0 ){
425 printf( " ERROR:表达式不合法\n " );
426 return ;
427 }
428 getNameId(str0, 0 ,s - 1 ); // 放在NAME[0],在下面进行归约时标识符id为0时表示出错
429 s += 2 ; // :=右边首字符
430 p = 0 ;
431 while (str0[s]){
432 if (isLetter(str0[s])){ // 标识符
433 t = s;
434 while (str0[t] && isLetter(str0[t]))t ++ ;
435 str[p] = ' i ' ;
436 str_name[p] = getNameId(str0,s,t - 1 );
437 s = t,p ++ ;
438 }
439 else { // 操作符
440 str[p] = str0[s];
441 s ++ ,p ++ ;
442 }
443 }
444 str[p] = ' # ' ; // 结束符
445 str[p + 1 ] = 0 ;
446 //
447
448 pair < int , int > STACK[ 1000 ]; // STACK[i].first保存id,正数是Tnode,负数是Nnode
449 // STACK[i].second保存标识符id
450 int k = 0 ,j;STACK[k].first = getTnodeId( ' # ' ); // STACK[k]栈顶
451 p = 0 ; // str[p]当前字符
452 int q,cid;
453
454 while (str[p]){
455 cid = getTnodeId(str[p]); // 当前字符id
456
457 if (STACK[k].first > 0 ) j = k;
458 else j = k - 1 ;
459
460 while (PRECEDENCETABLE[STACK[j].first][cid] == ' > ' ){
461 do {
462 q = STACK[j].first;
463 j = STACK[j - 1 ].first > 0 ? j - 1 :j - 2 ;
464 } while (PRECEDENCETABLE[STACK[j].first][q] == ' = ' );
465
466 int tmp_name = 0 ;
467 char tmp = reduction(STACK,j + 1 ,k,tmp_name); // 归约
468 k = j + 1 ;
469 STACK[k].first =- getNnodeId(tmp);
470 if (tmp_name)
471 STACK[k].second = tmp_name;
472 else // name为0表示错误
473 printf( " ERROR:tmp_name,when reduction " );
474 }
475 if (PRECEDENCETABLE[STACK[j].first][cid] == ' < ' ||
476 PRECEDENCETABLE[STACK[j].first][cid] == ' = ' ){
477 k ++ ;
478 STACK[k].first = cid,STACK[k].second = str_name[p];
479 p ++ ;
480 }
481 else {
482 if (str[p] == ' # ' && j == 0 ){
483
484 // 给:=左边的符号赋值
485 printf( " (:=,%s,_,%s)\n " ,NAME[STACK[ 1 ].second],NAME[ 0 ]);
486
487 printf( " Done!\n " );
488 return ;
489 }
490 else {
491 printf( " ERROR:归约时出错! " );
492 exit( - 1 );
493 }
494 }
495 }
496
497 }
498
499 /*
500 * 读入文法
501 */
502
503 void readGrammar(){
504 char str[ 30 ];
505
506 while (scanf( " %[^\n]%*c " ,str) != EOF){
507 /// 将空格去掉 ///
508 int s = 0 ,t = 0 ;
509 while (str[t]){
510 if (str[t] != ' ' ){
511 str[s] = str[t];
512 s ++ ;
513 }
514 t ++ ;
515 }
516 str[s] = 0 ;
517 //
518
519 if (str[ 0 ] < ' A ' || str[ 0 ] > ' Z ' ){ // 检查首字母是否大写
520 printf( " ERROR:首字母不是非终结符\n " );
521 continue ;
522 }
523 int p = 0 ;
524 while (str[p] && (str[p] != ' - ' || str[p + 1 ] != ' > ' )) p ++ ; // 检查是否有符号"->"
525 if ( ! str[p]){
526 printf( " ERROR:不是产生式\n " );
527 continue ;
528 }
529 p += 2 ;
530 /// 找终结符 ///
531 t = p;
532 while (str[t]){
533 if ( ! isNnode(str[t]) && str[t] != ' | ' )
534 insertT_ARRAY(str[t]);
535 t ++ ;
536 }
537 //
538
539 /// 找产生式 ///
540 while (str[p]){
541 s = t = p;
542 while (str[p] && str[p] != ' | ' ) p ++ ;
543 if (str[p]){
544 t = p - 1 ,p ++ ;
545 }
546 else
547 t = p;
548
549 insertN_ARRAY(str[ 0 ],str,s,t);
550 }
551 //
552 }
553 insertT_ARRAY( ' # ' ); // 加入终结符'#'
554 }
555
556 /*
557 * 算符优先文法主函数
558 */
559
560 void dealOperatorPrecedenceGrammar(){
561 freopen( " input31 " , " r " ,stdin);
562 freopen( " output3 " , " w " ,stdout);
563 readGrammar();
564 getFIRSTVT();
565 getLASTVT();
566 getPrecedenceTable();
567
568 freopen( " input32 " , " r " ,stdin);
569 char str[ 100 ];
570 while (scanf( " %[^\n]%*c " ,str) != EOF){
571 operatorPrecedenceParser(str);
572 }
573 }
2 *Author:Hu Wenbiao
3 *Created Time: Tue 16 Nov 2010 05:11:20 PM CST
4 *File Name: work3.cpp
5 *Description:算符优先文法
6 * 1.非终结符和终结符的编号(id)都是它们在数组中的下标
7 * 2.算法只能处理单字符的非终结符和终结符(大写字母为非终结符,
8 * 其他为终结符)
9 * 3.处理的表达式必须含有:=且其左边不能含有运算符,否则会被作为
10 * 标识符的一部分处理
11 * 4.表达式的标识符可以是字符串如:aa=bb+cc+dd*eef
12 * 5.处理表达式时先将标识符转化为i(因为文法中只用i表示标识符),
13 * 标识符的名称在NAME中记录,另外产生的中间标识符(如T1、E2)
14 * 的名称也在NAME中记录,名称的id为其下标,NAME[0]记录等号“:=”
15 * 左边的那个标识符,对于其他的标识符若id为0表示出错
16 \************************************************************** */
17 // *========================*Head File*========================*\\
18
19 #include < stack >
20 #include " work.h "
21
22 /* ----------------------*Global Variable*---------------------- */
23
24 N_NODE N_ARRAY[ 30 ]; // 非终端符数组(下标从1开始)
25 char T_ARRAY[ 30 ]; // 终端符数组(下标从1开始)
26 bool F[ 30 ][ 30 ],L[ 30 ][ 30 ]; // F[i][j]表示id为j的终结符是否属于
27 // id为i的非终结符的FIRSTVT,L相同。
28 stack < pair < int , int > > S; // 用于求FIRSTVT和LASTVT
29 char PRECEDENCETABLE[ 30 ][ 30 ]; // 算符优先关系表
30 char NAME[ 100 ][ 10 ]; // 用来存放标识符名称,NAME[i]表示id为i的标识符
31 int name_foot[ 100 ]; // 分配中间标识符的下标,如T1中的1
32 // *=======================*Main Program*=======================* //
33
34 int getTnodeId( char ch){ // 返回终端符编码(下标),不存在返回0
35 int p = 1 ;
36 while (T_ARRAY[p] && T_ARRAY[p] != ch) p ++ ;
37 if (T_ARRAY[p])
38 return p;
39 else
40 return 0 ;
41 }
42
43 int getNnodeId( char ch){ // 返回非终端符编码(下标),不存在返回0
44 int pos = 1 ;
45 while (N_ARRAY[pos].val && N_ARRAY[pos].val != ch) pos ++ ;
46 if (N_ARRAY[pos].val)
47 return pos;
48 else
49 return 0 ;
50 }
51
52 int getNameId( char * str, int s, int t){ // 给str[s]~str[t]分配位置,并返回id
53 int ptr = 0 ;
54 while (NAME[ptr][ 0 ])ptr ++ ;
55
56 for ( int i = 0 ;s + i <= t;i ++ )
57 NAME[ptr][i] = str[s + i];
58
59 return ptr;
60 }
61
62 int getNameId( char ch){ // 同上,重载
63 name_foot[ch] ++ ;
64 int ptr = 0 ;
65 while (NAME[ptr][ 0 ])ptr ++ ;
66
67 NAME[ptr][ 0 ] = ch;
68 NAME[ptr][ 1 ] = char (name_foot[ch] + ' 0 ' );
69
70 return ptr;
71 }
72
73 void insertN_ARRAY( char val, char * str, int s, int t){ // 增加非终结符
74 int pos = 1 ;
75 while (N_ARRAY[pos].val && N_ARRAY[pos].val != val) pos ++ ;
76 N_ARRAY[pos].val = val;
77 int cnt = N_ARRAY[pos].cnt,p = 0 ;
78 for (;s <= t;p ++ ,s ++ ){
79 N_ARRAY[pos].ARR[cnt][p] = str[s];
80 }
81 N_ARRAY[pos].cnt ++ ;
82 }
83
84 void insertT_ARRAY( char ch){ // 增加终结符
85 int p = 1 ;
86 while (T_ARRAY[p]) p ++ ;
87 T_ARRAY[p] = ch;
88 }
89
90 bool isNnode( char ch){ // 判断是否是非终结符
91 return ch >= ' A ' && ch <= ' Z ' ;
92 }
93
94 /*
95 * 求解所有非终结符的FIRSTVT
96 */
97
98 void getFIRSTVT(){
99 pair < int , int > cur; // cur.first是非终结符的id,cur.second是终结符的id
100 int nr_Nnode = 1 ;
101 while (N_ARRAY[nr_Nnode].val) nr_Nnode ++ ; // 其实nr_Nnode=(nr of Nnode)+1
102 for ( int i = 1 ;i < nr_Nnode;i ++ ){ // 每个非终结符
103 for ( int j = 0 ;j < N_ARRAY[i].cnt;j ++ ){ // 每个产生式
104 if ( ! isNnode(N_ARRAY[i].ARR[j][ 0 ])){ // N_ARRAY[i].ARR[j][0]是终结符
105 int id_Tnode = getTnodeId(N_ARRAY[i].ARR[j][ 0 ]);
106 if (F[i][id_Tnode]) continue ;
107 F[i][id_Tnode] = true ;
108 S.push(pair < int , int > (i,id_Tnode));
109 }
110 // N_ARRAY[i].ARR[j][1]是终结符
111 else if (N_ARRAY[i].ARR[j][ 1 ] && ! isNnode(N_ARRAY[i].ARR[j][ 1 ])){
112 int id_Tnode = getTnodeId(N_ARRAY[i].ARR[j][ 1 ]);
113 if (F[i][id_Tnode]) continue ;
114 F[i][id_Tnode] = true ;
115 S.push(pair < int , int > (i,id_Tnode));
116 }
117 }
118 }
119 while ( ! S.empty()){
120 cur = S.top(),S.pop();
121 char curNnodeVal = N_ARRAY[cur.first].val;
122
123 for ( int i = 1 ;i < nr_Nnode;i ++ ){
124 if (F[i][cur.second]) continue ; // cur.second已经属于FIRSTVT(i)
125 for ( int j = 0 ;j < N_ARRAY[i].cnt;j ++ ){ // 查找哪个产生式右边以curNnodeVal为首
126 if (N_ARRAY[i].ARR[j][ 0 ] == curNnodeVal){
127 F[i][cur.second] = true ;
128 S.push(pair < int , int > (i,cur.second));
129 break ;
130 }
131 }
132 }
133 }
134 /* 输出FIRSTVT */
135 for ( int i = 1 ;i < nr_Nnode;i ++ ){
136 for ( int j = 1 ;j < 30 ;j ++ ){
137 if (F[i][j]){
138 printf( " FIRSTVT(%c): { " ,N_ARRAY[i].val);
139 while (j < 30 ){
140 if (F[i][j])
141 printf( " %c " ,T_ARRAY[j]);
142 j ++ ;
143 }
144 printf( " }\n " );
145 }
146 }
147 }
148 printf( " \n " );
149 /**/
150 }
151
152 /*
153 * 求解所有非终结符的LASTVT
154 */
155
156 void getLASTVT(){
157 pair < int , int > cur;
158 int nr_Nnode = 1 ;
159 while (N_ARRAY[nr_Nnode].val) nr_Nnode ++ ;
160 for ( int i = 1 ;i < nr_Nnode;i ++ ){
161 for ( int j = 0 ;j < N_ARRAY[i].cnt;j ++ ){
162 int ptr = 0 ;
163 while (N_ARRAY[i].ARR[j][ptr]) ptr ++ ;
164 ptr -- ;
165 if ( ! isNnode(N_ARRAY[i].ARR[j][ptr])){
166 int id_Tnode = getTnodeId(N_ARRAY[i].ARR[j][ptr]);
167 if (L[i][id_Tnode]) continue ;
168 L[i][id_Tnode] = true ;
169 S.push(pair < int , int > (i,id_Tnode));
170 }
171 else if (ptr > 0 &&! isNnode(N_ARRAY[i].ARR[j][ptr - 1 ])){
172 int id_Tnode = getTnodeId(N_ARRAY[i].ARR[j][ptr - 1 ]);
173 if (L[i][id_Tnode]) continue ;
174 L[i][id_Tnode] = true ;
175 S.push(pair < int , int > (i,id_Tnode));
176 }
177 }
178 }
179 while ( ! S.empty()){
180 cur = S.top(),S.pop();
181 char curNnodeVal = N_ARRAY[cur.first].val;
182
183 for ( int i = 1 ;i < nr_Nnode;i ++ ){
184 for ( int j = 0 ;j < N_ARRAY[i].cnt;j ++ ){
185 int ptr = 0 ;
186 while (N_ARRAY[i].ARR[j][ptr]) ptr ++ ;
187 ptr -- ;
188 if (N_ARRAY[i].ARR[j][ptr] == curNnodeVal &&
189 ! L[i][cur.second]){
190 L[i][cur.second] = true ;
191 S.push(pair < int , int > (i,cur.second));
192 break ;
193 }
194 }
195 }
196 }
197 /* 输出LASTVT */
198 for ( int i = 1 ;i < nr_Nnode;i ++ ){
199 for ( int j = 1 ;j < 30 ;j ++ ){
200 if (L[i][j]){
201 printf( " LASTVT(%c): { " ,N_ARRAY[i].val);
202 while (j < 30 ){
203 if (L[i][j])
204 printf( " %c " ,T_ARRAY[j]);
205 j ++ ;
206 }
207 printf( " }\n " );
208 }
209 }
210 }
211 printf( " \n " );
212 /**/
213 }
214
215 /*
216 * 求算符优先表
217 */
218
219 void getPrecedenceTable(){
220 int nr_Nnode = 1 ,nr_Tnode = 1 ;
221 while (N_ARRAY[nr_Nnode].val) nr_Nnode ++ ;
222 while (T_ARRAY[nr_Tnode]) nr_Tnode ++ ;
223
224 /* *关于#的比较* */
225 int id_sharp = getTnodeId( ' # ' );
226 for ( int j = 1 ;j < nr_Tnode;j ++ ){
227 if (F[ 1 ][j]){
228 PRECEDENCETABLE[id_sharp][j] = ' < ' ;
229 }
230 if (L[ 1 ][j]){
231 PRECEDENCETABLE[j][id_sharp] = ' > ' ;
232 }
233 }
234
235 /* ************* */
236
237 for ( int i = 1 ;i < nr_Nnode;i ++ ){ // 每个非终结符
238 for ( int j = 0 ;j < N_ARRAY[i].cnt;j ++ ){ // 每个产生式
239 int tail = 0 ;
240 while (N_ARRAY[i].ARR[j][tail]) tail ++ ;
241 tail -- ; // 最后一位(非零)
242 for ( int p = 0 ;p < tail;p ++ ){
243 // tt
244 if ( ! isNnode(N_ARRAY[i].ARR[j][p]) &&
245 ! isNnode(N_ARRAY[i].ARR[j][p + 1 ])){
246 int id1 = getTnodeId(N_ARRAY[i].ARR[j][p]);
247 int id2 = getTnodeId(N_ARRAY[i].ARR[j][p + 1 ]);
248 if (PRECEDENCETABLE[id1][id2]){
249 printf( " ERROR:不是算符优先文法! " );
250 exit(EXIT_FAILURE);
251 }
252 PRECEDENCETABLE[id1][id2] = ' = ' ;
253 }
254 // tNt
255 if (p <= tail - 2 &&! isNnode(N_ARRAY[i].ARR[j][p]) &&
256 isNnode(N_ARRAY[i].ARR[j][p + 1 ]) &&
257 ! isNnode(N_ARRAY[i].ARR[j][p + 2 ])){
258 int id1 = getTnodeId(N_ARRAY[i].ARR[j][p]);
259 int id2 = getTnodeId(N_ARRAY[i].ARR[j][p + 2 ]);
260 if (PRECEDENCETABLE[id1][id2]){
261 printf( " ERROR:不是算符优先文法! " );
262 exit(EXIT_FAILURE);
263 }
264 PRECEDENCETABLE[id1][id2] = ' = ' ;
265 }
266 // tN
267 if ( ! isNnode(N_ARRAY[i].ARR[j][p]) &&
268 isNnode(N_ARRAY[i].ARR[j][p + 1 ])){
269 int id1 = getTnodeId(N_ARRAY[i].ARR[j][p]);
270 int id_Nnode = getNnodeId(N_ARRAY[i].ARR[j][p + 1 ]);
271 int id2 = 1 ;
272 while (T_ARRAY[id2]){
273 if (F[id_Nnode][id2]){
274 if (PRECEDENCETABLE[id1][id2]){
275 printf( " ERROR:不是算符优先文法! " );
276 exit(EXIT_FAILURE);
277 }
278 PRECEDENCETABLE[id1][id2] = ' < ' ;
279 }
280 id2 ++ ;
281 }
282 }
283 // Nt
284 if (isNnode(N_ARRAY[i].ARR[j][p]) &&
285 ! isNnode(N_ARRAY[i].ARR[j][p + 1 ])){
286 int id_Nnode = getNnodeId(N_ARRAY[i].ARR[j][p]);
287 int id2 = getTnodeId(N_ARRAY[i].ARR[j][p + 1 ]);
288 int id1 = 1 ;
289 while (T_ARRAY[id1]){
290 if (L[id_Nnode][id1]){
291 if (PRECEDENCETABLE[id1][id2]){
292 printf( " ERROR:不是算符优先方法! " );
293 exit(EXIT_FAILURE);
294 }
295 PRECEDENCETABLE[id1][id2] = ' > ' ;
296 }
297 id1 ++ ;
298 }
299 }
300 }
301 }
302 }
303 // 输出优先表 // //
304 cout << " " ;
305 for ( int i = 1 ;i < nr_Tnode;i ++ ){
306 cout << T_ARRAY[i] << " " ;
307 }
308 cout << endl;
309 for ( int i = 1 ;i < nr_Tnode;i ++ ){
310 cout << T_ARRAY[i] << " " ;
311 for ( int j = 1 ;j < nr_Tnode;j ++ ){
312 if (PRECEDENCETABLE[i][j])
313 cout << PRECEDENCETABLE[i][j] << " " ;
314 else
315 cout << " " ;
316 }
317 cout << endl;
318 }
319 cout << endl;
320 / /
321 }
322
323 /*
324 * 比较ARR[s]~ARR[t]中的id和str中的符号是否匹配
325 * 其中非终结符的id是取负值的,比较时也不比较非
326 * 终结符是否相同,只要求终结符相同,非终结符相
327 * 对应就返回true
328 */
329
330 bool cmpIdNodeVal(pair < int , int >* ARR, int s, int t, char * str){
331 int ptr = 0 ,id;
332 while (s <= t && str[ptr]){
333 if (isNnode(str[ptr])){ // 非终结符
334 if (ARR[s].first > 0 )
335 return false ;
336 }
337 else if (ARR[s].first != getTnodeId(str[ptr]))
338 return false ;
339 ptr ++ ;
340 s ++ ;
341 }
342 if (s <= t || str[ptr])
343 return false ;
344 return true ;
345 }
346
347 /*
348 * 将STACK[s]~STACK[t]归约,返回归约后的非终结符的值,
349 * 分配并由name返回非终结符的名称id
350 */
351
352 char reduction(pair < int , int >* STACK, int s, int t, int & name){
353 int i = 1 ;
354 while (N_ARRAY[i].val){
355 for ( int j = 0 ;j < N_ARRAY[i].cnt;j ++ ){
356 if (cmpIdNodeVal(STACK,s,t,N_ARRAY[i].ARR[j])){ // 查找成功
357
358
359 /// 输出 ///
360
361 if (s == t && STACK[s].first > 0 ){ // 1
362 name = STACK[s].second;
363 }
364
365 if (s + 1 == t){ // 2
366 name = getNameId(N_ARRAY[i].val);
367 if (STACK[s].first > 0 ){
368 printf( " (%c,_,%s,%s)\n " ,
369 T_ARRAY[STACK[s].first],NAME[STACK[t].second],NAME[name]);
370 }
371 else {
372 printf( " (%c,%s,_,%s)\n " ,
373 T_ARRAY[STACK[t].first],NAME[STACK[s].second],NAME[name]);
374 }
375 }
376 if (s + 2 == t){ // 3
377 if (STACK[s].first > 0 && STACK[t].first > 0 ){ // (T)这种情况
378 name = STACK[s + 1 ].second;
379 }
380 else {
381 name = getNameId(N_ARRAY[i].val);
382 printf( " (%c,%s,%s,%s)\n " ,T_ARRAY[STACK[s + 1 ].first],
383 NAME[STACK[s].second],NAME[STACK[t].second],NAME[name]);
384 }
385 }
386
387 / /
388
389 return N_ARRAY[i].val;
390 }
391 }
392 i ++ ;
393 }
394 return 0 ;
395 }
396
397 /*
398 * 核心函数,处理传入的单句表达式,要求表达式必须为
399 * abc:=x*y+zuv 的形式,即必须有:=号且其左边不能有运
400 * 算符,否则会被当作标识符的一部分处理
401 */
402
403 void operatorPrecedenceParser( char * str0){
404 /// 将空格去掉 ///
405 int s = 0 ,t = 0 ,p;
406 while (str0[t]){
407 if (str0[t] != ' ' ){
408 str0[s] = str0[t];
409 s ++ ;
410 }
411 t ++ ;
412 }
413 str0[s] = 0 ;
414
415 /// 将str0转换成str,由文法符号表示 ///
416 char str[ 1000 ];
417 int str_name[ 1000 ]; // str_name[i]是str[i]的名称,当str[i]为操作符时无意义
418
419 memset(NAME, 0 , sizeof (NAME));
420 memset(name_foot, 0 , sizeof (name_foot));
421
422 s = 0 ;
423 while (str0[s] && str0[s] != ' : ' )s ++ ;
424 if (str0[s] == 0 ){
425 printf( " ERROR:表达式不合法\n " );
426 return ;
427 }
428 getNameId(str0, 0 ,s - 1 ); // 放在NAME[0],在下面进行归约时标识符id为0时表示出错
429 s += 2 ; // :=右边首字符
430 p = 0 ;
431 while (str0[s]){
432 if (isLetter(str0[s])){ // 标识符
433 t = s;
434 while (str0[t] && isLetter(str0[t]))t ++ ;
435 str[p] = ' i ' ;
436 str_name[p] = getNameId(str0,s,t - 1 );
437 s = t,p ++ ;
438 }
439 else { // 操作符
440 str[p] = str0[s];
441 s ++ ,p ++ ;
442 }
443 }
444 str[p] = ' # ' ; // 结束符
445 str[p + 1 ] = 0 ;
446 //
447
448 pair < int , int > STACK[ 1000 ]; // STACK[i].first保存id,正数是Tnode,负数是Nnode
449 // STACK[i].second保存标识符id
450 int k = 0 ,j;STACK[k].first = getTnodeId( ' # ' ); // STACK[k]栈顶
451 p = 0 ; // str[p]当前字符
452 int q,cid;
453
454 while (str[p]){
455 cid = getTnodeId(str[p]); // 当前字符id
456
457 if (STACK[k].first > 0 ) j = k;
458 else j = k - 1 ;
459
460 while (PRECEDENCETABLE[STACK[j].first][cid] == ' > ' ){
461 do {
462 q = STACK[j].first;
463 j = STACK[j - 1 ].first > 0 ? j - 1 :j - 2 ;
464 } while (PRECEDENCETABLE[STACK[j].first][q] == ' = ' );
465
466 int tmp_name = 0 ;
467 char tmp = reduction(STACK,j + 1 ,k,tmp_name); // 归约
468 k = j + 1 ;
469 STACK[k].first =- getNnodeId(tmp);
470 if (tmp_name)
471 STACK[k].second = tmp_name;
472 else // name为0表示错误
473 printf( " ERROR:tmp_name,when reduction " );
474 }
475 if (PRECEDENCETABLE[STACK[j].first][cid] == ' < ' ||
476 PRECEDENCETABLE[STACK[j].first][cid] == ' = ' ){
477 k ++ ;
478 STACK[k].first = cid,STACK[k].second = str_name[p];
479 p ++ ;
480 }
481 else {
482 if (str[p] == ' # ' && j == 0 ){
483
484 // 给:=左边的符号赋值
485 printf( " (:=,%s,_,%s)\n " ,NAME[STACK[ 1 ].second],NAME[ 0 ]);
486
487 printf( " Done!\n " );
488 return ;
489 }
490 else {
491 printf( " ERROR:归约时出错! " );
492 exit( - 1 );
493 }
494 }
495 }
496
497 }
498
499 /*
500 * 读入文法
501 */
502
503 void readGrammar(){
504 char str[ 30 ];
505
506 while (scanf( " %[^\n]%*c " ,str) != EOF){
507 /// 将空格去掉 ///
508 int s = 0 ,t = 0 ;
509 while (str[t]){
510 if (str[t] != ' ' ){
511 str[s] = str[t];
512 s ++ ;
513 }
514 t ++ ;
515 }
516 str[s] = 0 ;
517 //
518
519 if (str[ 0 ] < ' A ' || str[ 0 ] > ' Z ' ){ // 检查首字母是否大写
520 printf( " ERROR:首字母不是非终结符\n " );
521 continue ;
522 }
523 int p = 0 ;
524 while (str[p] && (str[p] != ' - ' || str[p + 1 ] != ' > ' )) p ++ ; // 检查是否有符号"->"
525 if ( ! str[p]){
526 printf( " ERROR:不是产生式\n " );
527 continue ;
528 }
529 p += 2 ;
530 /// 找终结符 ///
531 t = p;
532 while (str[t]){
533 if ( ! isNnode(str[t]) && str[t] != ' | ' )
534 insertT_ARRAY(str[t]);
535 t ++ ;
536 }
537 //
538
539 /// 找产生式 ///
540 while (str[p]){
541 s = t = p;
542 while (str[p] && str[p] != ' | ' ) p ++ ;
543 if (str[p]){
544 t = p - 1 ,p ++ ;
545 }
546 else
547 t = p;
548
549 insertN_ARRAY(str[ 0 ],str,s,t);
550 }
551 //
552 }
553 insertT_ARRAY( ' # ' ); // 加入终结符'#'
554 }
555
556 /*
557 * 算符优先文法主函数
558 */
559
560 void dealOperatorPrecedenceGrammar(){
561 freopen( " input31 " , " r " ,stdin);
562 freopen( " output3 " , " w " ,stdout);
563 readGrammar();
564 getFIRSTVT();
565 getLASTVT();
566 getPrecedenceTable();
567
568 freopen( " input32 " , " r " ,stdin);
569 char str[ 100 ];
570 while (scanf( " %[^\n]%*c " ,str) != EOF){
571 operatorPrecedenceParser(str);
572 }
573 }
work.cpp
1
/*
**************************************************************\
2 *Author:Hu Wenbiao
3 *Created Time: Mon 15 Nov 2010 09:58:46 PM CST
4 *File Name: work.cpp
5 *Description:主函数
6 \************************************************************** */
7 // *========================*Head File*========================*\\
8
9 #include " work.h "
10 /* ----------------------*Global Variable*---------------------- */
11
12 // *=======================*Main Program*=======================* //
13
14 int main(){
15 init();
16 freopen( " input1 " , " r " ,stdin);
17 freopen( " output1 " , " w " ,stdout);
18 dealSourceCode();
19 freopen( " output1 " , " r " ,stdin);
20 freopen( " output2 " , " w " ,stdout);
21 morphologyAnalysis();
22
23 dealOperatorPrecedenceGrammar(); // 输入的设置在该函数中
24 }
2 *Author:Hu Wenbiao
3 *Created Time: Mon 15 Nov 2010 09:58:46 PM CST
4 *File Name: work.cpp
5 *Description:主函数
6 \************************************************************** */
7 // *========================*Head File*========================*\\
8
9 #include " work.h "
10 /* ----------------------*Global Variable*---------------------- */
11
12 // *=======================*Main Program*=======================* //
13
14 int main(){
15 init();
16 freopen( " input1 " , " r " ,stdin);
17 freopen( " output1 " , " w " ,stdout);
18 dealSourceCode();
19 freopen( " output1 " , " r " ,stdin);
20 freopen( " output2 " , " w " ,stdout);
21 morphologyAnalysis();
22
23 dealOperatorPrecedenceGrammar(); // 输入的设置在该函数中
24 }