编译原理实验3
@
实验三: Tiny扩充语言的语法分析
一、实验内容:
扩充的语法规则有:实现 while、do while、for、if语句、+= 加法赋值运算符号(类似于C语言的+=)、
求余%、乘方^、<=(小于等于)、<>(不等于)运算符号,具体文法规则自行构造。
可参考:云盘中参考书P97及P136的文法规则。
(1) While-stmt --> while(exp) stmt-sequence endwhile
(2) Dowhile-stmt-->do stmt-sequence while(exp);
(3) for-stmt-->for identifier:=simple-exp to simple-exp do stmt-sequence enddo 步长递增1
(4) for-stmt-->for identifier:=simple-exp downto simple-exp do stmt-sequence enddo 步长递减1
(5) += 加法赋值运算符号、求余%、乘方^、<=(小于等于)、<>(不等于)运算符号的文法规则请自行组织。
(6) 把TINY语言原有的if语句书写格式
if_stmt-->if exp then stmt-sequence end | | if exp then stmt-sequence else stmt-sequence end
改写为:
if_stmt-->if(exp) stmt-sequence else stmt-sequence | if(exp) stmt-sequence
(7)为了实现以上的扩充或改写功能,还需要对原tiny语言的文法规则做如何的处理?
二、要求:
(1)要提供一个源程序编辑界面,以让用户输入源程序(可保存、打开源程序)
(2)可由用户选择是否生成语法树,并可查看所生成的语法树。
(3)应该书写完善的软件文档
三、完成时间:四周(第9周-第13周)
四、上交方法:
由各班班长或学习委员将每个同学的实验源程序、可执行程序、测试用例、文档刻录成光盘。
五、完成方式:每个学生自行独立完成。
六、测试数据
测试文件1:
{ Sample program
in TINY language -
computes factorial
}
read x; { input an integer }
if (0<x) { don't compute if x <= 0 }
fact := 1;
do
fact := fact * x;
x := x - 1
while ( 0<x );
write fact; { output factorial of x }
测试文件2:
{ Sample program
in TINY language -
computes factorial
}
read x; { input an integer }
if ( 0<x ) { don't compute if x <= 0 }
for fact := x downto 1 do
fact := fact * x;
enddo
write fact; { output factorial of x }
测试文件3:
{ Sample program
in TINY language -
computes factorial
}
read x; { input an integer }
if ( 0<x ) { don't compute if x <= 0 }
fact := 1;
while(0<x)
fact := fact * x;
x := x - 1
endwhile
write fact; { output factorial of x }
为了做好全面的测试,你还需要增加相应的测试文件。
任务
扩充文法规则
更改前:
program -> stmt-sequence
stmt-sequence -> statement { ; statement }
statement -> if-stmt | repeat-stmt | assign-stmt | read-stmt | write-stmt
if-stmt -> if exp then stmt-sequence[else stmt-sequence] end
repeat-stmt -> repeat stmt-sequence until exp
assign-stmt -> identifier := exp
read-stmt -> read identifier
write-stmt -> write exp
exp -> simple-exp[comparison-op simple-exp]
comparison-op -> < | =
simple-exp -> term {addop term}
addop -> + | -
term -> factor {mulop factor}
mulop -> * | /
factor -> (exp) | number | identifier
更改后:
program -> stmt-sequence
stmt-sequence -> statement { ; statement }
statement -> if-stmt | repeat-stmt | assign-stmt | read-stmt | write-stmt | While-stmt | Dowhile-stmt | for-stmt
if-stmt -> if(exp)stmt-sequence[else stmt-sequence]
repeat-stmt -> repeat stmt-sequence until exp
assign-stmt -> identifier assignop exp
assignop -> [:= | +=]
read-stmt -> read identifier
write-stmt -> write exp
While-stmt -> while(exp) stmt-sequence endwhile
Dowhile-stmt -> do stmt-sequence while(exp)
for-stmt -> for identifier:=simple-exp [to | downto] simple-exp do stmt-sequence enddo
exp -> simple-exp[comparison-op simple-exp]
comparison-op -> < | = | <= | <>
simple-exp -> term {addop term}
addop -> + | -
term -> factor {mulop factor}
mulop -> * | / | %
factor -> powernum {powerop powernum}
powerop -> ^
powernum -> (exp) | number | identifier
改写对应parse代码
#include <iostream>
#include <fstream>
#include <string>
#include <string.h>
using namespace std;
/*********************************************************
创建核心类Core,功能为:
(1) 类中拥有属性fileString,并且该fileString内容
可以被更改
(2) char getNextChar(); 读取fileString中的字符
(3) Token getToken(); 返回Token对象(tokenType, tokenString)
(4) TreeNode * parse(); 返回一棵语法树
(5) string treeStr(); 将语法树以字符串的形式呈现
*********************************************************/
#define MAXRESERVED 15
#define TRUE 1
#define FALSE 0
enum TokenType
/* book-keeping tokens */
{ENDFILE,ERROR,
/* reserved words */
IF,THEN,ELSE,END,REPEAT,UNTIL,READ,WRITE,WHILE,ENDWHILE,
DO, ENDDO, FOR, TO, DOWNTO,
/* multicharacter tokens */
ID,NUM,
/* special symbols */
ASSIGN,EQ,LT,LTEQ,LTRT,PLUS,MINUS,TIMES,OVER,POWER,REM,
LPAREN,RPAREN,SEMI
};
enum StateType{ START,INASSIGN,INPLUS,INLT,INCOMMENT,INNUM,INID,DONE };
enum NodeKind{StmtK,ExpK};
enum StmtKind{IfK,RepeatK,AssignK,ReadK,WriteK,WhileK,DowhileK,ForK};
enum ExpKind{OpK,ConstK,IdK};
enum ExpType{Void,Integer,Boolean};
class TreeNode{
public:
TreeNode * child[3];
TreeNode * sibling;
NodeKind nodekind;
union {StmtKind stmtkind; ExpKind expkind;} kind;
union {
TokenType op;
int val;
char * name;
}attr;
char * forType;
ExpType type;
};
struct Token{
TokenType type;
string str;
Token(TokenType t=END, string s=""){
type = t;
str = s;
}
Token(const Token &token){
type = token.type;
str = token.str;
}
};
struct{
string tokenString;
TokenType tokenType;
}reservedWords[MAXRESERVED]
= {{"if",IF},{"then",THEN},{"else",ELSE},{"end",END},
{"repeat",REPEAT},{"until",UNTIL},{"read",READ},
{"write",WRITE},{"while", WHILE},{"endwhile", ENDWHILE},
{"do", DO}, {"for", FOR}, {"to", TO}, {"downto", DOWNTO},
{"enddo", ENDDO}};
class Core{
public:
string fileString = ""; //
int strIndex = 0;
Token token = Token();
public:
string run(const string &fs);
public:
TreeNode * parse(); //生成语法树
string treeStr(TreeNode * root, int num); //获取语法数的字符串形式
Token getToken(); //获取token
char getNextChar(); //获取字符
void delTree(TreeNode * root);//删除语法树(防止系统开辟的动态内存过多)
TreeNode * stmt_sequence();
TreeNode * statement();
TreeNode * if_stmt();
TreeNode * repeat_stmt();
TreeNode * assign_stmt();
TreeNode * read_stmt();
TreeNode * write_stmt();
TreeNode * while_stmt();
TreeNode * dowhile_stmt();
TreeNode * for_stmt();
TreeNode * exp();
TreeNode * simple_exp();
TreeNode * term();
TreeNode * factor();
TreeNode * powernum();
void match(TokenType expected);
TreeNode * newStmtNode(StmtKind kind);
TreeNode * newExpNode(ExpKind kind);
TokenType reservedLookup(string TokenString);
static string tokenTypeStr(TokenType token);
};
string Core::run(const string &fs){
strIndex = 0;
fileString = fs;
TreeNode * root = parse();
string result = treeStr(root, 0);
delTree(root);
return result;
}
TreeNode * Core::parse(){
TreeNode * t;
token = getToken();
t = stmt_sequence();
if (token.type != ENDFILE)
cout << "Code ends before file" << endl;
return t;
}
string Core::treeStr(TreeNode * root, int num){
string all = "";
while(root != nullptr){
string a = "";
for(int i=0; i<num; ++i)
a += " ";
if(root->nodekind==StmtK){
switch(root->kind.stmtkind){
case IfK:
a += "IF\n";
break;
case RepeatK:
a += "Repeat\n";
break;
case AssignK:
a += "Assign to ";
a += root->attr.name;
a += '\n';
break;
case ReadK:
a += "Read ";
a += root->attr.name;
a += '\n';
break;
case WriteK:
a += "Write\n";
break;
case WhileK:
a += "While\n";
break;
case DowhileK:
a += "Dowhile\n";
break;
case ForK:
a += "For ";
a += root->attr.name;
a += root->forType;
a += '\n';
break;
default:
break;
}
}
else{
switch(root->kind.expkind){
case OpK:
a += "Op: ";
a += tokenTypeStr(root->attr.op);
a += '\n';
break;
case ConstK:
a += "Const: ";
a += to_string(root->attr.val);
a += '\n';
break;
case IdK:
a += "Id: ";
a += root->attr.name;
a += '\n';
break;
default:
break;
}
}
for(int i=0; i<3; ++i){
a += treeStr(root->child[i], num+2);
}
root = root->sibling;
all += a;
}
return all;
}
void Core::delTree(TreeNode * root){
if(root == nullptr)
return;
delTree(root->sibling);
for(int i=0; i<3; ++i)
delTree(root->child[i]);
delete root;
}
char Core::getNextChar(){
return fileString[strIndex++];
}
Token Core::getToken(){
TokenType tokenType;
string tokenString = "";
StateType state = START;
int save;
while (state != DONE){
char c = getNextChar();
save = TRUE;
switch (state)
{
case START:
if (isdigit(c))
state = INNUM;
else if (isalpha(c))
state = INID;
else if (c == ':')
state = INASSIGN;
else if (c == '+')
state = INPLUS;
else if (c == '<')
state = INLT;
else if ((c == ' ') || (c == '\t') || (c == '\n'))
save = FALSE;
else if (c == '{')
{ save = FALSE;
state = INCOMMENT;
}
else{
state = DONE;
switch (c){
case '\0':
save = FALSE;
tokenType = ENDFILE;
break;
case '=':
tokenType = EQ;
break;
case '-':
tokenType = MINUS;
break;
case '*':
tokenType = TIMES;
break;
case '/':
tokenType = OVER;
break;
case '^':
tokenType = POWER;
break;
case '%':
tokenType = REM;
break;
case '(':
tokenType = LPAREN;
break;
case ')':
tokenType = RPAREN;
break;
case ';':
tokenType = SEMI;
break;
default:
tokenType = ERROR;
break;
}
}
break;
case INCOMMENT:
save = FALSE;
if (c == '\0')
{ state = DONE;
tokenType = ENDFILE;
}
else if (c == '}') state = START;
break;
case INASSIGN:
state = DONE;
if (c == '=')
tokenType = ASSIGN;
else{
--strIndex;
save = FALSE;
tokenType = ERROR;
}
break;
case INPLUS:
state = DONE;
if(c == '=')
tokenType = ASSIGN;
else{
--strIndex;
save = FALSE;
tokenType = PLUS;
}
break;
case INLT:
state = DONE;
if(c == '=')
tokenType = LTEQ;
else if(c == '>')
tokenType = LTRT;
else{
--strIndex;
save = FALSE;
tokenType = LT;
}
break;
case INNUM:
if (!isdigit(c))
{ /* backup in the input */
--strIndex;
save = FALSE;
state = DONE;
tokenType = NUM;
}
break;
case INID:
if (!isalpha(c))
{ /* backup in the input */
--strIndex;
save = FALSE;
state = DONE;
tokenType = ID;
}
break;
case DONE:
default: /* should never happen */
state = DONE;
tokenType = ERROR;
break;
}
if (save)
tokenString += c;
if (state == DONE)
{
if (tokenType == ID)
tokenType = reservedLookup(tokenString);
}
}
return Token(tokenType, tokenString);
}
TokenType Core::reservedLookup(string tokenString){
for(int i=0; i<MAXRESERVED; ++i){
if (tokenString == reservedWords[i].tokenString)
return reservedWords[i].tokenType;
}
return ID;
}
TreeNode * Core::stmt_sequence(){
TreeNode * t = statement();
TreeNode * p = t;
TreeNode * q;
match(SEMI);
while((token.type==IF) || (token.type==REPEAT) ||
(token.type==ID) || (token.type==READ) || (token.type==WRITE) ||
(token.type==WHILE) || (token.type==DO) || (token.type==FOR)){
q = statement();
if(q!=nullptr){
if(t==nullptr) t = p = q;
else{
p->sibling = q;
p = q;
}
}
match(SEMI);
}
return t;
}
TreeNode * Core::statement()
{ TreeNode * t = nullptr;
switch (token.type) {
case IF : t = if_stmt(); break;
case REPEAT : t = repeat_stmt(); break;
case ID : t = assign_stmt(); break;
case READ : t = read_stmt(); break;
case WRITE : t = write_stmt(); break;
case WHILE : t = while_stmt(); break;
case DO: t = dowhile_stmt(); break;
case FOR: t = for_stmt(); break;
default:
token = getToken();
break;
}
return t;
}
TreeNode * Core::if_stmt(void)
{ TreeNode * t = newStmtNode(IfK);
match(IF);
match(LPAREN);
if (t!=nullptr) t->child[0] = exp();
match(RPAREN);
if (t!=nullptr) t->child[1] = stmt_sequence();
if (token.type==ELSE) {
match(ELSE);
if (t!=nullptr) t->child[2] = stmt_sequence();
}
return t;
}
TreeNode * Core::repeat_stmt(void)
{ TreeNode * t = newStmtNode(RepeatK);
match(REPEAT);
if (t!=nullptr) t->child[0] = stmt_sequence();
match(UNTIL);
if (t!=nullptr) t->child[1] = exp();
return t;
}
TreeNode * Core::assign_stmt(void)
{ TreeNode * t = newStmtNode(AssignK);
if ((t!=nullptr) && (token.type==ID)){
t->attr.name = new char[token.str.size()+1];
strcpy(t->attr.name, token.str.c_str());
}
match(ID);
match(ASSIGN);
if (t!=nullptr) t->child[0] = exp();
return t;
}
TreeNode * Core::read_stmt(void)
{ TreeNode * t = newStmtNode(ReadK);
match(READ);
if ((t!=nullptr) && (token.type==ID)){
t->attr.name = new char[token.str.size()+1];
strcpy(t->attr.name, token.str.c_str());
}
match(ID);
return t;
}
TreeNode * Core::write_stmt(void)
{ TreeNode * t = newStmtNode(WriteK);
match(WRITE);
if (t!=nullptr) t->child[0] = exp();
return t;
}
TreeNode * Core::while_stmt(void){
TreeNode * t = newStmtNode(WhileK);
match(WHILE);
match(LPAREN);
if(t!=nullptr) t->child[0] = exp();
match(RPAREN);
if(t!=nullptr) t->child[1] = stmt_sequence();
match(ENDWHILE);
return t;
}
TreeNode * Core::dowhile_stmt(void){
TreeNode * t = newStmtNode(DowhileK);
match(DO);
if(t!=nullptr) t->child[0] = stmt_sequence();
match(WHILE);
match(LPAREN);
if(t!=nullptr) t->child[1] = exp();
match(RPAREN);
return t;
}
TreeNode * Core::for_stmt(void){
TreeNode * t = newStmtNode(ForK);
if ((t!=nullptr) && (token.type==ID)){
t->attr.name = new char[token.str.size()+1];
strcpy(t->attr.name, token.str.c_str());
}
match(ID);
match(ASSIGN);
if (t!=nullptr) t->child[0] = simple_exp();
if(token.type == TO){
t->forType = "To";
match(TO);
}
else{
t->forType = "Downto";
match(DOWNTO);
}
if (t!=nullptr) t->child[1] = simple_exp();
match(DO);
if (t!=nullptr) t->child[2] = stmt_sequence();
match(ENDDO);
return t;
}
TreeNode * Core::exp(void)
{ TreeNode * t = simple_exp();
if ((token.type==LT)||(token.type==EQ)||(token.type==LTEQ)||(token.type==LTRT)) {
TreeNode * p = newExpNode(OpK);
if (p!=nullptr) {
p->child[0] = t;
p->attr.op = token.type;
t = p;
}
match(token.type);
if (t!=nullptr)
t->child[1] = simple_exp();
}
return t;
}
TreeNode * Core::simple_exp(void)
{ TreeNode * t = term();
while ((token.type==PLUS)||(token.type==MINUS)||(token.type==REM))
{ TreeNode * p = newExpNode(OpK);
if (p!=nullptr) {
p->child[0] = t;
p->attr.op = token.type;
t = p;
match(token.type);
t->child[1] = term();
}
}
return t;
}
TreeNode * Core::term(void)
{ TreeNode * t = factor();
while ((token.type==TIMES)||(token.type==OVER))
{ TreeNode * p = newExpNode(OpK);
if (p!=nullptr) {
p->child[0] = t;
p->attr.op = token.type;
t = p;
match(token.type);
p->child[1] = factor();
}
}
return t;
}
TreeNode * Core::factor(void){
TreeNode * t = powernum();
while(token.type==POWER){
TreeNode * p = newExpNode(OpK);
if(p!=nullptr){
p->child[0] = t;
p->attr.op = token.type;
t = p;
match(token.type);
p->child[1] = powernum();
}
}
return t;
}
TreeNode * Core::powernum(void)
{ TreeNode * t = nullptr;
switch (token.type) {
case NUM :
t = newExpNode(ConstK);
if ((t!=nullptr) && (token.type==NUM))
t->attr.val = stoi(token.str);
match(NUM);
break;
case ID :
t = newExpNode(IdK);
if ((t!=nullptr) && (token.type==ID)){
t->attr.name = new char[token.str.size()+1];
strcpy(t->attr.name, token.str.c_str());
}
match(ID);
break;
case LPAREN :
match(LPAREN);
t = exp();
match(RPAREN);
break;
default:
token = getToken();
break;
}
return t;
}
void Core::match(TokenType expected)
{
if (token.type == expected) token = getToken();
}
TreeNode * Core::newStmtNode(StmtKind kind)
{
TreeNode * t = new TreeNode();
int i;
if (t==nullptr)
cout << "Out of memory error at line\n";
else {
for (i=0;i<3;i++) t->child[i] = nullptr;
t->sibling = nullptr;
t->nodekind = StmtK;
t->kind.stmtkind = kind;
}
return t;
}
TreeNode * Core::newExpNode(ExpKind kind)
{
TreeNode * t = new TreeNode();
int i;
if (t==nullptr)
cout << "Out of memory error at line\n";
else {
for (i=0;i<3;i++) t->child[i] = nullptr;
t->sibling = nullptr;
t->nodekind = ExpK;
t->kind.expkind = kind;
t->type = Void;
}
return t;
}
string Core::tokenTypeStr(TokenType token){
switch(token){
case 0:
return "ENDFILE";
case 1:
return "ERROR";
case 2:
return "IF";
case 3:
return "THEN";
case 4:
return "ELSE";
case 5:
return "END";
case 6:
return "REPEAT";
case 7:
return "UNTIL";
case 8:
return "READ";
case 9:
return "WRITE";
case 10:
return "WHILE";
case 11:
return "ENDWHILE";
case 12:
return "DO";
case 13:
return "ENDDO";
case 14:
return "FOR";
case 15:
return "TO";
case 16:
return "DOWNTO";
case 17:
return "ID";
case 18:
return "NUM";
case 19:
return "ASSIGN";
case 20:
return "EQ";
case 21:
return "LT";
case 22:
return "LTEQ";
case 23:
return "LTRT";
case 24:
return "PLUS";
case 25:
return "MINUS";
case 26:
return "TIMES";
case 27:
return "OVER";
case 28:
return "POWER";
case 29:
return "REM";
case 30:
return "LPAREN";
case 31:
return "RPAREN";
case 32:
return "SEMI";
}
}
int main(){
ifstream in("source.tny", ios::in);
istreambuf_iterator<char> beg(in), end;
string str(beg, end);
in.close();
Core core;
string result = core.run(str);
cout << result;
}
可视化界面(QT)
代码
global.h
#ifndef _GLOBAL_H_
#define _GLOBAL_H_
#include <string>
using namespace std;
#define MAXRESERVED 15
#define TRUE 1
#define FALSE 0
enum TokenType
/* book-keeping tokens */
{ENDFILE,ERROR,
/* reserved words */
IF,THEN,ELSE,END,REPEAT,UNTIL,READ,WRITE,WHILE,ENDWHILE,
DO, ENDDO, FOR, TO, DOWNTO,
/* multicharacter tokens */
ID,NUM,
/* special symbols */
ASSIGN,EQ,LT,LTEQ,LTRT,PLUS,MINUS,TIMES,OVER,POWER,REM,
LPAREN,RPAREN,SEMI
};
enum StateType{ START,INASSIGN,INPLUS,INLT,INCOMMENT,INNUM,INID,DONE };
enum NodeKind{StmtK,ExpK};
enum StmtKind{IfK,RepeatK,AssignK,ReadK,WriteK,WhileK,DowhileK,ForK};
enum ExpKind{OpK,ConstK,IdK};
enum ExpType{Void,Integer,Boolean};
class TreeNode{
public:
TreeNode * child[3];
TreeNode * sibling;
NodeKind nodekind;
union {StmtKind stmtkind; ExpKind expkind;} kind;
union {
TokenType op;
int val;
char * name;
}attr;
char * forType;
ExpType type;
};
struct Token{
TokenType type;
string str;
Token(TokenType t=END, string s=""){
type = t;
str = s;
}
Token(const Token &token){
type = token.type;
str = token.str;
}
};
struct{
string tokenString;
TokenType tokenType;
}reservedWords[MAXRESERVED]
= {{"if",IF},{"then",THEN},{"else",ELSE},{"end",END},
{"repeat",REPEAT},{"until",UNTIL},{"read",READ},
{"write",WRITE},{"while", WHILE},{"endwhile", ENDWHILE},
{"do", DO}, {"for", FOR}, {"to", TO}, {"downto", DOWNTO},
{"enddo", ENDDO}};
#endif
core.h
#ifndef _CORE_H_
#define _CORE_H_
#include <string>
#include "global.h"
using namespace std;
class Core{
public:
string fileString = ""; //
int strIndex = 0;
Token token = Token();
public:
string run(const string &fs);
public:
TreeNode * parse(); //生成语法树
string treeStr(TreeNode * root, int num); //获取语法数的字符串形式
Token getToken(); //获取token
char getNextChar(); //获取字符
void delTree(TreeNode * root);//删除语法树(防止系统开辟的动态内存过多)
TreeNode * stmt_sequence();
TreeNode * statement();
TreeNode * if_stmt();
TreeNode * repeat_stmt();
TreeNode * assign_stmt();
TreeNode * read_stmt();
TreeNode * write_stmt();
TreeNode * while_stmt();
TreeNode * dowhile_stmt();
TreeNode * for_stmt();
TreeNode * exp();
TreeNode * simple_exp();
TreeNode * term();
TreeNode * factor();
TreeNode * powernum();
void match(TokenType expected);
TreeNode * newStmtNode(StmtKind kind);
TreeNode * newExpNode(ExpKind kind);
TokenType reservedLookup(string TokenString);
static string tokenTypeStr(TokenType token);
};
#endif
core.cpp
#include <iostream>
#include <fstream>
#include <string>
#include <string.h>
#include "core.h"
using namespace std;
/*********************************************************
创建核心类Core,功能为:
(1) 类中拥有属性fileString,并且该fileString内容
可以被更改
(2) char getNextChar(); 读取fileString中的字符
(3) Token getToken(); 返回Token对象(tokenType, tokenString)
(4) TreeNode * parse(); 返回一棵语法树
(5) string treeStr(); 将语法树以字符串的形式呈现
*********************************************************/
string Core::run(const string &fs){
strIndex = 0;
fileString = fs;
TreeNode * root = parse();
string result = treeStr(root, 0);
delTree(root);
return result;
}
TreeNode * Core::parse(){
TreeNode * t;
token = getToken();
t = stmt_sequence();
if (token.type != ENDFILE)
cout << "Code ends before file" << endl;
return t;
}
string Core::treeStr(TreeNode * root, int num){
string all = "";
while(root != nullptr){
string a = "";
for(int i=0; i<num; ++i)
a += " ";
if(root->nodekind==StmtK){
switch(root->kind.stmtkind){
case IfK:
a += "IF\n";
break;
case RepeatK:
a += "Repeat\n";
break;
case AssignK:
a += "Assign to ";
a += root->attr.name;
a += '\n';
break;
case ReadK:
a += "Read ";
a += root->attr.name;
a += '\n';
break;
case WriteK:
a += "Write\n";
break;
case WhileK:
a += "While\n";
break;
case DowhileK:
a += "Dowhile\n";
break;
case ForK:
a += "For ";
a += root->attr.name;
a += " ";
a += root->forType;
a += '\n';
break;
default:
break;
}
}
else{
switch(root->kind.expkind){
case OpK:
a += "Op: ";
a += tokenTypeStr(root->attr.op);
a += '\n';
break;
case ConstK:
a += "Const: ";
a += to_string(root->attr.val);
a += '\n';
break;
case IdK:
a += "Id: ";
a += root->attr.name;
a += '\n';
break;
default:
break;
}
}
for(int i=0; i<3; ++i){
a += treeStr(root->child[i], num+2);
}
root = root->sibling;
all += a;
}
return all;
}
void Core::delTree(TreeNode * root){
if(root == nullptr)
return;
delTree(root->sibling);
for(int i=0; i<3; ++i)
delTree(root->child[i]);
delete root;
}
char Core::getNextChar(){
return fileString[strIndex++];
}
Token Core::getToken(){
TokenType tokenType;
string tokenString = "";
StateType state = START;
int save;
while (state != DONE){
char c = getNextChar();
save = TRUE;
switch (state)
{
case START:
if (isdigit(c))
state = INNUM;
else if (isalpha(c))
state = INID;
else if (c == ':')
state = INASSIGN;
else if (c == '+')
state = INPLUS;
else if (c == '<')
state = INLT;
else if ((c == ' ') || (c == '\t') || (c == '\n'))
save = FALSE;
else if (c == '{')
{ save = FALSE;
state = INCOMMENT;
}
else{
state = DONE;
switch (c){
case '\0':
save = FALSE;
tokenType = ENDFILE;
break;
case '=':
tokenType = EQ;
break;
case '-':
tokenType = MINUS;
break;
case '*':
tokenType = TIMES;
break;
case '/':
tokenType = OVER;
break;
case '^':
tokenType = POWER;
break;
case '%':
tokenType = REM;
break;
case '(':
tokenType = LPAREN;
break;
case ')':
tokenType = RPAREN;
break;
case ';':
tokenType = SEMI;
break;
default:
tokenType = ERROR;
break;
}
}
break;
case INCOMMENT:
save = FALSE;
if (c == '\0')
{ state = DONE;
tokenType = ENDFILE;
}
else if (c == '}') state = START;
break;
case INASSIGN:
state = DONE;
if (c == '=')
tokenType = ASSIGN;
else{
--strIndex;
save = FALSE;
tokenType = ERROR;
}
break;
case INPLUS:
state = DONE;
if(c == '=')
tokenType = ASSIGN;
else{
--strIndex;
save = FALSE;
tokenType = PLUS;
}
break;
case INLT:
state = DONE;
if(c == '=')
tokenType = LTEQ;
else if(c == '>')
tokenType = LTRT;
else{
--strIndex;
save = FALSE;
tokenType = LT;
}
break;
case INNUM:
if (!isdigit(c))
{ /* backup in the input */
--strIndex;
save = FALSE;
state = DONE;
tokenType = NUM;
}
break;
case INID:
if (!isalpha(c))
{ /* backup in the input */
--strIndex;
save = FALSE;
state = DONE;
tokenType = ID;
}
break;
case DONE:
default: /* should never happen */
state = DONE;
tokenType = ERROR;
break;
}
if (save)
tokenString += c;
if (state == DONE)
{
if (tokenType == ID)
tokenType = reservedLookup(tokenString);
}
}
return Token(tokenType, tokenString);
}
TokenType Core::reservedLookup(string tokenString){
for(int i=0; i<MAXRESERVED; ++i){
if (tokenString == reservedWords[i].tokenString)
return reservedWords[i].tokenType;
}
return ID;
}
TreeNode * Core::stmt_sequence(){
TreeNode * t = statement();
TreeNode * p = t;
TreeNode * q;
match(SEMI);
while((token.type==IF) || (token.type==REPEAT) ||
(token.type==ID) || (token.type==READ) || (token.type==WRITE) ||
(token.type==WHILE) || (token.type==DO) || (token.type==FOR)){
q = statement();
if(q!=nullptr){
if(t==nullptr) t = p = q;
else{
p->sibling = q;
p = q;
}
}
match(SEMI);
}
return t;
}
TreeNode * Core::statement()
{ TreeNode * t = nullptr;
switch (token.type) {
case IF : t = if_stmt(); break;
case REPEAT : t = repeat_stmt(); break;
case ID : t = assign_stmt(); break;
case READ : t = read_stmt(); break;
case WRITE : t = write_stmt(); break;
case WHILE : t = while_stmt(); break;
case DO: t = dowhile_stmt(); break;
case FOR: t = for_stmt(); break;
default:
token = getToken();
break;
}
return t;
}
TreeNode * Core::if_stmt(void)
{ TreeNode * t = newStmtNode(IfK);
match(IF);
match(LPAREN);
if (t!=nullptr) t->child[0] = exp();
match(RPAREN);
if (t!=nullptr) t->child[1] = stmt_sequence();
if (token.type==ELSE) {
match(ELSE);
if (t!=nullptr) t->child[2] = stmt_sequence();
}
return t;
}
TreeNode * Core::repeat_stmt(void)
{ TreeNode * t = newStmtNode(RepeatK);
match(REPEAT);
if (t!=nullptr) t->child[0] = stmt_sequence();
match(UNTIL);
if (t!=nullptr) t->child[1] = exp();
return t;
}
TreeNode * Core::assign_stmt(void)
{ TreeNode * t = newStmtNode(AssignK);
if ((t!=nullptr) && (token.type==ID)){
t->attr.name = new char[token.str.size()+1];
strcpy(t->attr.name, token.str.c_str());
}
match(ID);
match(ASSIGN);
if (t!=nullptr) t->child[0] = exp();
return t;
}
TreeNode * Core::read_stmt(void)
{ TreeNode * t = newStmtNode(ReadK);
match(READ);
if ((t!=nullptr) && (token.type==ID)){
t->attr.name = new char[token.str.size()+1];
strcpy(t->attr.name, token.str.c_str());
}
match(ID);
return t;
}
TreeNode * Core::write_stmt(void)
{ TreeNode * t = newStmtNode(WriteK);
match(WRITE);
if (t!=nullptr) t->child[0] = exp();
return t;
}
TreeNode * Core::while_stmt(void){
TreeNode * t = newStmtNode(WhileK);
match(WHILE);
match(LPAREN);
if(t!=nullptr) t->child[0] = exp();
match(RPAREN);
if(t!=nullptr) t->child[1] = stmt_sequence();
match(ENDWHILE);
return t;
}
TreeNode * Core::dowhile_stmt(void){
TreeNode * t = newStmtNode(DowhileK);
match(DO);
if(t!=nullptr) t->child[0] = stmt_sequence();
match(WHILE);
match(LPAREN);
if(t!=nullptr) t->child[1] = exp();
match(RPAREN);
return t;
}
TreeNode * Core::for_stmt(void){
TreeNode * t = newStmtNode(ForK);
match(FOR);
if ((t!=nullptr) && (token.type==ID)){
t->attr.name = new char[token.str.size()+1];
strcpy(t->attr.name, token.str.c_str());
}
match(ID);
match(ASSIGN);
if (t!=nullptr) t->child[0] = simple_exp();
if(token.type == TO){
t->forType = "To";
match(TO);
}
else{
t->forType = "Downto";
match(DOWNTO);
}
if (t!=nullptr) t->child[1] = simple_exp();
match(DO);
if (t!=nullptr) t->child[2] = stmt_sequence();
match(ENDDO);
return t;
}
TreeNode * Core::exp(void)
{ TreeNode * t = simple_exp();
if ((token.type==LT)||(token.type==EQ)||(token.type==LTEQ)||(token.type==LTRT)) {
TreeNode * p = newExpNode(OpK);
if (p!=nullptr) {
p->child[0] = t;
p->attr.op = token.type;
t = p;
}
match(token.type);
if (t!=nullptr)
t->child[1] = simple_exp();
}
return t;
}
TreeNode * Core::simple_exp(void)
{ TreeNode * t = term();
while ((token.type==PLUS)||(token.type==MINUS)||(token.type==REM))
{ TreeNode * p = newExpNode(OpK);
if (p!=nullptr) {
p->child[0] = t;
p->attr.op = token.type;
t = p;
match(token.type);
t->child[1] = term();
}
}
return t;
}
TreeNode * Core::term(void)
{ TreeNode * t = factor();
while ((token.type==TIMES)||(token.type==OVER))
{ TreeNode * p = newExpNode(OpK);
if (p!=nullptr) {
p->child[0] = t;
p->attr.op = token.type;
t = p;
match(token.type);
p->child[1] = factor();
}
}
return t;
}
TreeNode * Core::factor(void){
TreeNode * t = powernum();
while(token.type==POWER){
TreeNode * p = newExpNode(OpK);
if(p!=nullptr){
p->child[0] = t;
p->attr.op = token.type;
t = p;
match(token.type);
p->child[1] = powernum();
}
}
return t;
}
TreeNode * Core::powernum(void)
{ TreeNode * t = nullptr;
switch (token.type) {
case NUM :
t = newExpNode(ConstK);
if ((t!=nullptr) && (token.type==NUM))
t->attr.val = stoi(token.str);
match(NUM);
break;
case ID :
t = newExpNode(IdK);
if ((t!=nullptr) && (token.type==ID)){
t->attr.name = new char[token.str.size()+1];
strcpy(t->attr.name, token.str.c_str());
}
match(ID);
break;
case LPAREN :
match(LPAREN);
t = exp();
match(RPAREN);
break;
default:
token = getToken();
break;
}
return t;
}
void Core::match(TokenType expected)
{
if (token.type == expected) token = getToken();
}
TreeNode * Core::newStmtNode(StmtKind kind)
{
TreeNode * t = new TreeNode();
int i;
if (t==nullptr)
cout << "Out of memory error at line\n";
else {
for (i=0;i<3;i++) t->child[i] = nullptr;
t->sibling = nullptr;
t->nodekind = StmtK;
t->kind.stmtkind = kind;
}
return t;
}
TreeNode * Core::newExpNode(ExpKind kind)
{
TreeNode * t = new TreeNode();
int i;
if (t==nullptr)
cout << "Out of memory error at line\n";
else {
for (i=0;i<3;i++) t->child[i] = nullptr;
t->sibling = nullptr;
t->nodekind = ExpK;
t->kind.expkind = kind;
t->type = Void;
}
return t;
}
string Core::tokenTypeStr(TokenType token){
switch(token){
case 0:
return "ENDFILE";
case 1:
return "ERROR";
case 2:
return "IF";
case 3:
return "THEN";
case 4:
return "ELSE";
case 5:
return "END";
case 6:
return "REPEAT";
case 7:
return "UNTIL";
case 8:
return "READ";
case 9:
return "WRITE";
case 10:
return "WHILE";
case 11:
return "ENDWHILE";
case 12:
return "DO";
case 13:
return "ENDDO";
case 14:
return "FOR";
case 15:
return "TO";
case 16:
return "DOWNTO";
case 17:
return "ID";
case 18:
return "NUM";
case 19:
return "ASSIGN";
case 20:
return "EQ";
case 21:
return "LT";
case 22:
return "LTEQ";
case 23:
return "LTRT";
case 24:
return "PLUS";
case 25:
return "MINUS";
case 26:
return "TIMES";
case 27:
return "OVER";
case 28:
return "POWER";
case 29:
return "REM";
case 30:
return "LPAREN";
case 31:
return "RPAREN";
case 32:
return "SEMI";
}
}
mywindow.h
#ifndef _MYWINDOW_H_
#define _MYWINDOW_H_
#include <QMainWindow>
#include <QPlainTextEdit>
#include "core.h"
class Mywindow : public QMainWindow{
Q_OBJECT
private:
QPlainTextEdit * edit1, * edit2;
QAction * openAction;
QAction * saveAction;
QAction * runAction;
Core * core;
public:
explicit Mywindow(QWidget *parent = nullptr);
signals: //用来声明信号函数
public slots: //用来声明槽函数
void open();
void save();
void run();
};
#endif
mywindow.cpp
#include "mywindow.h"
#include <QAction>
#include <QMenuBar>
#include <QToolBar>
#include <QHBoxLayout>
#include <iostream>
#include <QFileDialog>
#include <fstream>
using namespace std;
Mywindow::Mywindow(QWidget * parent) : QMainWindow(parent){
setWindowTitle(tr("Main Window"));
//文本编辑框
edit1 = new QPlainTextEdit(this);
edit2 = new QPlainTextEdit(this);
QWidget * cw = new QWidget();
QHBoxLayout * layout = new QHBoxLayout(cw);
layout->addWidget(edit1);
layout->addWidget(edit2);
setCentralWidget(cw);
//动作
openAction = new QAction(QIcon(":/images/open"), tr("&Open..."), this);
openAction->setStatusTip(tr("Open a source file"));
runAction = new QAction(QIcon(":/images/run"), tr("&Run..."), this);
runAction->setStatusTip(tr("Run the program"));
saveAction = new QAction(QIcon(":/images/save"), tr("&Save..."), this);
saveAction->setStatusTip(tr("Save the source file"));
connect(openAction, SIGNAL(triggered()), this, SLOT(open()));
connect(runAction, SIGNAL(triggered()), this, SLOT(run()));
connect(saveAction, SIGNAL(triggered()), this, SLOT(save()));
//工具栏
QToolBar * openToolBar = addToolBar(tr("&Open"));
openToolBar->addAction(openAction);
QToolBar * saveToolBar = addToolBar(tr("&Save"));
saveToolBar->addAction(saveAction);
QToolBar * runToolBar = addToolBar(tr("&Run"));
runToolBar->addAction(runAction);
//状态栏
statusBar();
//core
core = new Core();
}
void Mywindow::open(){
QString openfilename = QFileDialog::getOpenFileName(this,
tr("Open File"), "", "", 0);
if(!openfilename.isNull()){
string filename = openfilename.toStdString();
ifstream in(filename, ios::in);
istreambuf_iterator<char> beg(in), end;
string str(beg, end);
in.close();
edit1->setPlainText(QString::fromStdString(str));
}
}
void Mywindow::save(){
QString savefilename = QFileDialog::getSaveFileName(this,
tr("Open Config"), "", "Config Files (*.tny)");
if(!savefilename.isNull()){
string filename = savefilename.toStdString();
fstream out(filename, ios::out);
out << edit1->toPlainText().toStdString();
out.close();
}
}
void Mywindow::run(){
QString s = edit1->toPlainText();
QString result = QString::fromStdString(core->run(s.toStdString()));
edit2->setPlainText(result);
}
main.cpp
#include "mywindow.h"
#include <QApplication>
int main(int argc, char *argv[]){
//应用程序抽象类
QApplication app(argc, argv);
//窗口
Mywindow w;
w.show();
//进入消息循环,一直接受消息,直到窗口被关闭
return app.exec();
}
res.qrc
<RCC>
<qresource prefix="/images">
<file alias="open">open.jpg</file>
</qresource>
<qresource prefix="/images/">
<file alias="run">run.jpg</file>
</qresource>
<qresource prefix="/images/">
<file alias="save">save.jpg</file>
</qresource>
</RCC>