📄 plx.cpp
字号:
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <string.h>
#include <ctype.h>
#include <vector>
using namespace std;
#define LINELEN 256
/******************************************************************************\
* 全局类型 *
\******************************************************************************/
enum TOKENTYPE { TT_IDENT, TT_KEYWORD, TT_SYMBOL, TT_NUMBER };
enum KEYWORD {
KW_AND, KW_BEGIN, KW_DO, KW_ELSE, KW_END, KW_FALSE,
KW_IF, KW_INTEGER, KW_LOGICAL, KW_NOT, KW_OR, KW_PROGRAM,
KW_REPEAT, KW_THEN, KW_TRUE, KW_UNTIL, KW_WHILE, KW_WRITE
};
struct TOKEN {
TOKENTYPE type;
union {
char *ident;
KEYWORD keyword;
int symbol;
int number;
};
int line, col;
};
struct VAR {
char *name;
bool logic;
};
enum OPCODE { OP_INT, OP_HLT, OP_LIT, OP_LOD, OP_STO, OP_JMP, OP_JPC, OP_OPR };
struct INSTRUCT {
OPCODE op;
int n;
};
/******************************************************************************\
* 全局变量 *
\******************************************************************************/
const char *KeywordTab[] = {
"and", "begin", "do", "else", "end", "false",
"if", "integer", "logical", "not", "or", "program",
"repeat", "then", "true", "until", "while", "write",
NULL
};
const char *OpcodeTab[] = {
"INT", "HLT", "LIT", "LOD", "STO", "JMP", "JPC", "OPR"
};
FILE *SourceFile;
char LineBuf[LINELEN], *LinePtr;
int LineNum, ColNum;
int ErrNum;
TOKEN Token;
vector<char*> IdentTab;
vector<VAR> VarTab;
vector<INSTRUCT> InstTab;
int ProgCount;
vector<int> DataStack;
bool Pause;
/******************************************************************************\
* 输出出错信息 *
\******************************************************************************/
void ErrMsg(const char *msg, int line = 0, int col = 0)
{
if(line == 0) line = Token.line, col = Token.col;
printf("Line %04d:\t%s\n\t\t", line, LineBuf);
while(col)
{
printf(" ");
col--;
}
printf("^ %s\n", msg);
ErrNum++;
}
/******************************************************************************\
* 词法分析器 *
\******************************************************************************/
void GetToken()
{
for(;;)
{
if(*LinePtr == '\0') // 读新的一行源文件
{
if(fgets(LineBuf, LINELEN, SourceFile) == NULL)
{
ErrMsg("遇到意外的文件结束", LineNum, ColNum);
throw new int;
}
char *p = LineBuf;
while(*p && *p <= ' ') p++;
strcpy(LineBuf, p); // 去除行首的空白字符
p = strchr(LineBuf, '\n');
if(p) *p = 0; // 去除行尾的换行符
LinePtr = LineBuf;
LineNum++; ColNum = 0;
}
else if(*LinePtr <= ' ') // 跳过空白字符
{
if(*LinePtr == '\t') // 空白字符是Tab则调整列号到下一个制表位
ColNum += 8 - ColNum % 8;
else
ColNum++;
LinePtr++;
}
else if(isdigit(*LinePtr))
{
int num = 0;
Token.type = TT_NUMBER;
Token.line = LineNum; Token.col = ColNum;
do {
num = num * 10 + (*LinePtr++ - '0');
ColNum++;
} while(isdigit(*LinePtr));
Token.number = num;
break;
}
else if(isalpha(*LinePtr)) // 标识符(也可能是关键字)
{
char buf[LINELEN], *p = buf;
const char **q;
while(isalpha(*LinePtr) || isdigit(*LinePtr))
*p++ = tolower(*LinePtr++); // 转换为小写字符(大小写不敏感)
*p = 0;
for(q = KeywordTab; *q && strcmp(buf, *q); q++);
if(*q)
{
Token.type = TT_KEYWORD; // 是关键字
Token.keyword = KEYWORD(q - KeywordTab);
}
else
{
Token.type = TT_IDENT; // 是标识符
for(vector<char*>::iterator i = IdentTab.begin(); i != IdentTab.end() && strcmp(*i, buf); i++);
if(i == IdentTab.end())
{
Token.ident = new char[p - buf + 1];
strcpy(Token.ident, buf);
IdentTab.push_back(Token.ident);
}
else
Token.ident = *i;
}
Token.line = LineNum; Token.col = ColNum;
ColNum += p - buf;
break;
}
else // 运算符、分隔符
{
int symbol = 0;
switch(*LinePtr)
{
case ',':
case ';':
case '.':
case '(':
case ')':
case '+':
case '-':
case '*':
case '=':
symbol = *LinePtr;
break;
case ':':
if(LinePtr[1] == '=') symbol = ':=';
break;
case '/':
if(LinePtr[1] == '=') symbol = '/=';
else symbol = '/';
break;
case '<':
if(LinePtr[1] == '=') symbol = '<=';
else symbol = '<';
break;
case '>':
if(LinePtr[1] == '=') symbol = '>=';
else symbol = '>';
break;
}
if(symbol)
{
Token.type = TT_SYMBOL;
Token.symbol = symbol;
Token.line = LineNum; Token.col = ColNum;
if(symbol > 255)
LinePtr += 2, ColNum += 2; // 双字符
else
LinePtr++, ColNum++; // 单字符
break;
}
ErrMsg("非法字符", LineNum, ColNum);
LinePtr++; ColNum++;
}
}
}
bool OpenSourceFile(const char *filename)
{
if((SourceFile = fopen(filename, "r")) == NULL)
return false;
LinePtr = LineBuf, LineBuf[0] = '\0';
LineNum = 0;
IdentTab.clear();
GetToken();
return true;
}
bool IsKeyword(KEYWORD kw)
{
return Token.type == TT_KEYWORD && Token.keyword == kw;
}
bool IsSymbol(int sym)
{
return Token.type == TT_SYMBOL && Token.symbol == sym;
}
/******************************************************************************\
* 代码生成 *
\******************************************************************************/
void NewInst(OPCODE op, int n)
{
INSTRUCT inst = { op, n };
InstTab.push_back(inst);
}
int CurProgCount()
{
return InstTab.size();
}
void BackPatch(int pos, int n)
{
InstTab[pos].n = n;
}
void PrintInst(int pos)
{
printf("%04d\t%s%8d", pos, OpcodeTab[InstTab[pos].op], InstTab[pos].n);
}
/******************************************************************************\
* 语法分析、语义分析 *
\******************************************************************************/
// 在变量表中搜索指定变量并返回变量的地址。找不到则返回-1。
int FindVar(const char *name)
{
int i;
vector<VAR>::iterator p;
for(i = 0, p = VarTab.begin(); p != VarTab.end() && p->name != name; i++, p++);
if(p == VarTab.end())
return -1;
return i;
}
void AnalyzeDS()
{
for(;;)
{
if(IsKeyword(KW_BEGIN)) break;
if(IsKeyword(KW_INTEGER) || IsKeyword(KW_LOGICAL))
{
bool logic = IsKeyword(KW_LOGICAL);
GetToken();
for(;;)
{
if(Token.type == TT_IDENT)
{
if(FindVar(Token.ident) >= 0)
ErrMsg("标识符重定义");
else
{
VAR v = { Token.ident, logic };
VarTab.push_back(v);
}
GetToken();
}
else
{
ErrMsg("缺少标识符");
while(!(IsSymbol(',') || IsSymbol(';')))
GetToken();
}
if(!IsSymbol(',')) break;
GetToken();
}
if(IsSymbol(';'))
GetToken();
else if(IsKeyword(KW_INTEGER) || IsKeyword(KW_LOGICAL))
ErrMsg("缺少“;”");
}
else
{
ErrMsg("缺少类型说明符");
while(!(IsKeyword(KW_INTEGER) || IsKeyword(KW_LOGICAL) || IsKeyword(KW_BEGIN)))
GetToken();
}
}
}
void AnalyzeAE();
void AnalyzeAF()
{
if(Token.type == TT_IDENT)
{
int disp = FindVar(Token.ident);
if(disp < 0)
ErrMsg("标识符未定义");
else if(VarTab[disp].logic)
ErrMsg("标识符应为数值型变量");
GetToken();
NewInst(OP_LOD, disp);
}
else if(Token.type == TT_NUMBER)
{
NewInst(OP_LIT, Token.number);
GetToken();
}
else if(IsSymbol('-'))
{
GetToken();
AnalyzeAF();
NewInst(OP_OPR, 0);
}
else if(IsSymbol('('))
{
GetToken();
AnalyzeAE();
if(IsSymbol(')'))
GetToken();
else
{
ErrMsg("缺少“)”");
while(!(IsSymbol(')') || IsSymbol(';') || Token.type == TT_KEYWORD))
GetToken();
}
}
else
{
ErrMsg("非法表达式项");
while(!(IsSymbol(')') || IsSymbol(';') || Token.type == TT_KEYWORD))
GetToken();
}
}
void AnalyzeAT()
{
AnalyzeAF();
while(IsSymbol('*') || IsSymbol('/'))
{
int sym = Token.symbol;
GetToken();
AnalyzeAF();
NewInst(OP_OPR, sym == '*' ? 3 : 4);
}
}
void AnalyzeAE()
{
AnalyzeAT();
while(IsSymbol('+') || IsSymbol('-'))
{
int sym = Token.symbol;
GetToken();
AnalyzeAT();
NewInst(OP_OPR, sym == '+' ? 1 : 2);
}
}
void AnalyzeRE()
{
AnalyzeAE();
if(IsSymbol('=') || IsSymbol('/=') || IsSymbol('<') || IsSymbol('<=') || IsSymbol('>') || IsSymbol('>='))
{
int sym = Token.symbol;
GetToken();
AnalyzeAE();
switch(sym)
{
case '=': NewInst(OP_OPR, 8); break;
case '/=': NewInst(OP_OPR, 9); break;
case '<': NewInst(OP_OPR, 10); break;
case '<=': NewInst(OP_OPR, 11); break;
case '>': NewInst(OP_OPR, 12); break;
case '>=': NewInst(OP_OPR, 13); break;
}
}
else
{
ErrMsg("缺少关系运算符");
while(!(IsSymbol(')') || IsSymbol(';') || Token.type == TT_KEYWORD))
GetToken();
}
}
void AnalyzeBE();
void AnalyzeBF()
{
if(Token.type == TT_IDENT)
{
int disp = FindVar(Token.ident);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -