编译原理实验报告
LL(1)grammar:LL(1)分析法
operator precedence grammar算符优先分析法
一、LL(1)、OPG
LL(1)分析法:功能是利用LL(1)控制程序根据显示栈栈顶内容、向前看符号以及LL(1)分析表,对输入符号串自上而下的分析过程。
算符优先分析法:是一种简单直观、广泛使用、便于手工实现的自下而上的语法分析方法。定义算符之间的某种优先关系,寻找“归约串”,并进行归约。
二、LL(1)步骤
1.创建test2.txt
i+i*i#
2.源代码
代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
using namespace std;
struct Stack {
char s[30];
int top; //栈顶指针
}Stack;
char v1[6] = { 'i','+','*','(',')','#' };//终结符
char v2[5] = { 'E','G','T','S','F' };//非终结符
//预测分析表,用符号^来代替ε
char table[5][6][4] = { { "TG","","","","TG","" },
{ "","+TG","","","^","^" },
{ "FS","","","FS","","" },
{ "","^","*FS","","^","^" },
{ "i","","","(E)","","" } };
void push(char ch) {
Stack.s[Stack.top] = ch;
Stack.top++;
}
char pop() {
Stack.top--;
return Stack.s[Stack.top];
}
/**逆序进栈**/
void InversePush(int row, int line) {
char temp[4];
int i;
for (i = 0; i < 4; i++) {
if (table[row][line][i] != '\0')//字符串结束位是'\0'
temp[i] = table[row][line][i];
else {
temp[i] = '\0';
break;
}
}
if (i == 0)
return;
cout << v2[row] << "->";
for (int k = 0; k < i; k++)
cout << temp[k];
cout << endl;
for (i = i - 1; i >= 0; i--) {
if (temp[i] != '^') //^代表ε
push(temp[i]);
}
}
/**判断X是否为终结符**/
int IsTerminal(char X) {//若是则返回下标,非终结符返回-1
for (int i = 0; i<6; i++) {
if (X == v1[i])
return i;
}
return -1;
}
/**查找预测表**/
bool FindTable(char X, char a) {//若为空白则出错,否则进栈
int row;
for (row = 0; row < 5; row++){
if (X == v2[row])
break;
}
if (row == 5)
return false;
int line = IsTerminal(a);
if (line == -1)
return false;
if (table[row][line][0] == '\0')
return false;
else
InversePush(row, line);
return true;
}
int main()
{
FILE *fp;
char a, X;
bool flag = true;
char str[20];
int len = 0;
// if (() != NULL) {
// printf("error opening.\n");
// exit(1);
// }
fp = fopen("D:\\VS1\\code2\\compile\\ll1grammar\\test2.txt", "r");
Stack.top = 0;
push('#'); //栈底放一个’#’
push('E');//放入文法开始符号
a = fgetc(fp);
str[len] = a;
str[++len] = '\0';
while (flag) {
X = pop();
if (X == '#') {
if (a == '#') {
cout << str << "是合法符号串" << endl;
system("pause");
return 0;
}
}
else if ((IsTerminal(X)) != -1) {//栈顶是终结符
if (a == X) {//栈顶和输入串第一个字符进行抵消
a = fgetc(fp);
str[len] = a;
str[++len] = '\0';
}
else {
flag = false;
}
}
else if (!FindTable(X, a))
flag = false;
}
cout << str << "是非法符号串" << endl;
fclose(fp);
fp = NULL;
system("pause");
return 0;
}
2.实验结果
三、OPG步骤
1.源代码
代码如下:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <stack>
#include <map>
#include <set>
#include <algorithm>
#include <string>
#include <cstdlib>
#include <cctype>
#define MAX 507
using namespace std;
class WF
{
public:
string left;
vector<string> right;
WF ( const string& str )
{
left = str;
}
void insert ( char str[] )
{
right.push_back(str);
}
void print ( )
{
printf ( "%s->%s" , left.c_str() , right[0].c_str() );
for ( int i = 1 ; i < right.size() ; i++ )
printf ( "|%s" , right[i].c_str() );
puts("");
}
};
char relation[MAX][MAX];
vector<char> VT;
vector<WF> VN_set;
map<string,int> VN_dic;
set<char> first[MAX];
set<char> last[MAX];
int used[MAX];
int vis[MAX];
void dfs ( int x )
{
if ( vis[x] ) return;
vis[x] = 1;
string& left = VN_set[x].left;
for ( int i = 0 ; i < VN_set[x].right.size() ; i++ )
{
string& str = VN_set[x].right[i];
if ( isupper(str[0]) )
{
int y = VN_dic[str.substr(0,1)]-1;
if ( str.length() > 1 && !isupper(str[1] ) )
first[x].insert ( str[1] );
dfs ( y );
set<char>::iterator it = first[y].begin();
for ( ; it!= first[y].end() ; it++ )
first[x].insert ( *it );
}
else
first[x].insert ( str[0] );
}
}
void make_first ( )
{
memset ( vis , 0 , sizeof ( vis ) );
for ( int i = 0 ; i < VN_set.size() ; i++ )
if ( vis[i] ) continue;
else dfs ( i );
#define DEBUG
#ifdef DEBUG
puts("------------FIRSTVT集-------------------");
for ( int i = 0 ; i < VN_set.size() ; i++ )
{
printf ( "%s : " , VN_set[i].left.c_str() );
set<char>::iterator it = first[i].begin();
for ( ; it!= first[i].end() ; it++ )
printf ( "%c " , *it );
puts ("" );
}
#endif
}
void dfs1 ( int x )
{
if ( vis[x] ) return;
vis[x] = 1;
string& left = VN_set[x].left;
for ( int i = 0 ; i < VN_set[x].right.size() ; i++ )
{
string& str = VN_set[x].right[i];
int n = str.length() -1;
if ( isupper(str[n] ) )
{
int y = VN_dic[str.substr(n,1)]-1;
if ( str.length() > 1 && !isupper(str[n-1]) )
last[x].insert ( str[1] );
dfs1 ( y );
set<char>::iterator it = last[y].begin();
for ( ; it != last[y].end() ; it++ )
last[x].insert ( *it );
}
else
last[x].insert ( str[n] );
}
}
void make_last ( )
{
memset ( vis , 0 , sizeof ( vis ) );
for ( int i = 0 ; i < VN_set.size() ; i++ )
if ( vis[i] ) continue;
else dfs1 ( i );
#define DEBUG
#ifdef DEBUG
puts("--------------LASTVT集---------------------");
for ( int i = 0 ; i < VN_set.size() ; i++ )
{
printf ( "%s : " , VN_set[i].left.c_str() );
set<char>::iterator it = last[i].begin();
for ( ; it!= last[i].end() ; it++ )
printf ( "%c " , *it );
puts ("" );
}
#endif
}
void make_table ( )
{
for ( int i = 0 ; i < MAX ; i++ )
for ( int j = 0 ; j < MAX ; j++ )
relation[i][j] = ' ';
for ( int i = 0 ; i < VN_set.size() ; i++ )
for ( int j = 0 ; j < VN_set[i].right.size() ; j++ )
{
string& str = VN_set[i].right[j];
for ( int k = 0 ; k < str.length()-1 ; k++ )
{
if ( !isupper(str[k]) && !isupper(str[k+1]) )
relation[str[k]][str[k+1]] = '=';
if ( !isupper(str[k]) && isupper(str[k+1]) )
{
int x = VN_dic[str.substr(k+1,1)]-1;
set<char>::iterator it = first[x].begin();
for ( ; it != first[x].end() ; it++ )
relation[str[k]][*it] = '<';
}
if ( isupper(str[k]) && !isupper(str[k+1]) )
{
int x = VN_dic[str.substr(k,1)]-1;
set<char>::iterator it = last[x].begin();
for ( ; it != last[x].end() ; it++ )
relation[*it][str[k+1]] = '>';
}
if ( k > str.length()-2 ) continue;
if ( !isupper(str[k]) && !isupper(str[k+2]) && isupper(str[k+1]) )
relation[str[k]][str[k+2]] = '=';
}
}
#define DEBUG
#ifdef DEBUG
for ( int i = 0 ; i < VT.size()*5 ; i++ )
printf ("-");
printf ( "算符优先关系表" );
for ( int i = 0 ; i < VT.size()*5 ; i++ )
printf ( "-" );
puts("");
printf ( "|%8s|" , "" );
for ( int i = 0 ; i < VT.size() ; i++ )
printf ( "%5c%5s" , VT[i] , "|" );
puts ("");
for ( int i = 0 ; i < (VT.size()+1)*10 ; i++ )
printf ("-");
puts("");
for ( int i = 0 ; i < VT.size() ; i++ )
{
printf ( "|%4c%5s" , VT[i] , "|");
for ( int j = 0 ; j < VT.size() ; j++ )
printf ( "%5c%5s" , relation[VT[i]][VT[j]] , "|" );
puts ("");
for ( int i = 0 ; i < (VT.size()+1)*10 ; i++ )
printf ("-");
puts("");
}
#endif
}
int main()
{
int n;
char s[MAX];
while ( ~scanf ( "%d" , &n ) )
{
memset ( used , 0 , sizeof ( used ) );
for ( int i = 0 ; i < n ; i++ )
{
scanf ( "%s" , s );
int len = strlen(s),j;
for ( j = 0 ; j < len ; j++ )
if ( s[j] == '-' )
break;
s[j] = 0;
if ( !VN_dic[s] )
{
VN_set.push_back ( WF(s) );
VN_dic[s] = VN_set.size();
}
int x = VN_dic[s]-1;
VN_set[x].insert ( s+j+2 );
for ( int k = 0 ; k < j; k++ )
if ( !isupper(s[k] ) )
{
if ( used[s[k]] ) continue;
used[s[k]] = 1;
VT.push_back ( s[k] );
}
for ( int k = j+2 ; k < len; k++ )
if ( !isupper(s[k] ) )
{
if ( used[s[k]] ) continue;
VT.push_back ( s[k] );
used[s[k]] = VT.size();
}
}
#define DEBUG
#ifdef DEBUG
puts ("************VT集*******************");
for ( int i = 0 ; i < VT.size() ; i++ )
printf ( "%c " , VT[i] );
puts ("");
puts("*************产生式*****************");
for ( int i = 0 ; i < VN_set.size() ; i++ )
VN_set[i].print();
puts("************************************");
#endif
make_first();
make_last();
make_table();
}
printf("按Ctrl+Z退出");
system("pause");
}
2.输入:
5
S->a
S->^
S->(T)
T->T,S
T->S