📄 casl.y
字号:
%{
#include <windows.h>
#include <math.h>
#include <malloc.h>
#include <stdlib.h>
#include <algorithm>
#include "../Common/GlobalVariableDef.h"
#include "../Common/FileMapping.h"
LPVOID l;
//Casl.l中定义的存放当前编译的源文件行号的全局变量的外部引用声明!
extern int g_iLineNumber;
//--------------------标识当前编译过程中有没有发现错误------------------------------------
bool g_bCompilingErr = false;
//-------------当前的寄存器编号(0, 1, 2, 3, 4)--------------------------
int g_iCurrentRegNumber;
//-------------当前EA使用的变址寄存器的编号(0, 1, 2, 3, 4)--------------
int g_iCurrentEARegNumber;
//-------------当前被解析的指令的序号(从零开始)-------------------------
int g_lCurrentParseCodeNumber = 0;
//----------------------当前的有效地址操作数中的相对地址数据-----------------
EAAddress g_currentEAAddress;
//-----------------------当前的字符串常量-------------------------------------
string g_strCurrentStrConst;
//-----------------------当前的标号名称 -------------------------------------
string g_strCurrentLabel;
//-----------------------当前的常量-------------------------------------------
CaslConst g_currentConst;
//-------------------------标号表----------------------------------------------
//表中的每一个元素都是一个Map
//以标号名称 (string类型)为标号的Key
//标号所对应的指令的位置(long)为value
LabelMap g_mapLabel;
//-------------------------生成中间代码过程中使用的临时中间代码变量-------------
IntermediateCode g_tempCode;
//------存放编译过程中发现的错误信息-----------------------
vector<CompilingErrMsg> g_vecErrMsg;
//-----存放编译过程中仅能发现但未识别具体性质的错误-------------------------
vector<CompilingErrMsg> g_verUnknownErrMsg;
int yyerror(char *s);
int yylex(void);
void showErrMsg(char *s);
char g_szErrMsg[200];
CompilingErrMsg g_tmpErrMsg;
%}
%token NEW_LINE
%token CASL_DECIMAL
%token HEX
%token ID
%token STR
%token LABEL
%token DS
%token DC
%token GR0
%token GR1
%token GR2
%token GR3
%token GR4
%token LD
%token ST
%token LEA
%token ADD
%token SUB
%token AND
%token OR
%token EOR
%token CPA
%token CPL
%token SLA
%token SRA
%token SLL
%token SRL
%token JMP
%token JPZ
%token JMI
%token JNZ
%token JZE
%token PUSH
%token POP
%token CALL
%token RET
%token START
%token END
%token CASL_YACC_IN
%token CASL_YACC_OUT
%token EXIT
%%
PROGRAM: START BODY END NEW_LINE_STMT {printf("Input Ok!\n");};
| START BODY
{
g_tmpErrMsg.iLine = g_iLineNumber - 1;
g_tmpErrMsg.uiMsgID = NO_END_LABEL;
g_vecErrMsg.push_back(g_tmpErrMsg);
}
| BODY END NEW_LINE_STMT {
g_tmpErrMsg.iLine = g_iLineNumber - 1;
g_tmpErrMsg.uiMsgID = NO_START_LABEL;
g_vecErrMsg.push_back(g_tmpErrMsg);
}
;
NEW_LINE_STMT: NEW_LINE NEW_LINE_STMT | ;
BODY: EXECSTMT BODY | EXECSTMT ;
EXECSTMT: MEMSTMT |
MATHSTMT |
LOGSTMT |
RELSTMT |
CONDSTMT |
STACKSTMT|
PROCSTMT |
MACROSTMT |
EMPTYSTMT |
DEFSTMT |
error { g_tmpErrMsg.iLine = g_iLineNumber;}
NEW_LINE
{
g_tmpErrMsg.uiMsgID = INVALID_INSTRUCTION_TYPE;
g_vecErrMsg.push_back(g_tmpErrMsg);
}
;
DEFSTMT: DSDEF | DCDEF
DSDEF: LBLSTMT DS CASL_DECIMAL NEW_LINE
{
g_vecVariable.push_back(CaslVariable((char*)$1, $3));
if (NULL != $1)
{
free((char*)$1);
}
}
;
DCDEF: LBLSTMT DC CONST NEW_LINE
{
if ($1 != NULL)
{
strcpy(g_currentConst.strLabelName, (char*)$1);
}
else
{
strcpy(g_currentConst.strLabelName, "\0");
}
g_vecConst.push_back(g_currentConst);
if (NULL != $1)
{
free((char*)$1);
}
}
;
CONST: HEX
{
g_currentConst.type = HEX_CONST;
g_currentConst.constData.hexVal = $1;
}
| CASL_DECIMAL
{
g_currentConst.type = DEC_CONST;
g_currentConst.constData.decVal = $1;
}
| LABEL
{
g_currentConst.type = LABEL_CONST;
strcpy(g_currentConst.constData.labelVal, (char*)$1);
//free((char*)$1);
}
| STR
{
g_currentConst.type = STR_CONST;
strcpy(g_currentConst.constData.strVal, g_strCurrentStrConst.c_str());
}
;
EMPTYSTMT: NEW_LINE;
MEMSTMT: LDSTMT | LEASTMT | STSTMT
LDSTMT: LBLSTMT LD GR','EA NEW_LINE
{
//如果标号不为空
if (NULL != $1)
{
g_mapLabel.insert(LabelMap::value_type(g_lCurrentParseCodeNumber, (char*)$1));
free((char*)$1);
}
//对于每条指令前的标号应当怎样处理呢?
//应当定义一张标号表,然后将遇到的所有的标号都
//存放到标号表中,但是怎样将标号与实际的指令对应起来呢?
//考虑在程序中定义一个当前编译PC指针用来标识当前指令的
//位置,这样就可以在最后依据这个位置编号来确定标号所对应的指令的偏移
//而对于常量定义,变量定义就不参与PC指针的记数,
//而是在生成中间代码以后,依据,常量表,变量表,为所有的变量,常量
//分配空间,然后将程序中引用到变量,常量的地方改为变量,常量的地址值
g_tempCode.type = CASL_LD;
g_tempCode.operand1.type = REG_OPERAND;
g_tempCode.operand1.OperandVal.regOperand.regNumber = g_iCurrentRegNumber;
g_tempCode.operand2.type = EA_OPERAND;
//对于EA地址操作数的处理比较麻烦!!!!!!
g_tempCode.operand2.OperandVal.eaOperand.regNumber = g_iCurrentEARegNumber;
g_tempCode.operand2.OperandVal.eaOperand.address = g_currentEAAddress;
g_tempCode.iSrcCodeLineNumber = g_iLineNumber - 1;
g_vecIntermediateCode.push_back(g_tempCode);
//将下一个Parse的代码的编号加一
g_lCurrentParseCodeNumber++;
}
;
LBLSTMT: LABEL NEW_LINE
{
$$ = $1;
}
| LABEL
{
$$ = $1;
}
|
{
$$ = NULL;
}
;
GR: GR0
{
g_iCurrentRegNumber = 0;
}
| GR1
{
g_iCurrentRegNumber = 1;
}
| GR2
{
g_iCurrentRegNumber = 2;
}
| GR3
{
g_iCurrentRegNumber = 3;
}
| GR4
{
g_iCurrentRegNumber = 4;
}
;
EA: ADDR XRADDR
{
}
;
ADDR: CASL_DECIMAL
{
g_currentEAAddress.type = DEC_EA_ADDRESS;
g_currentEAAddress.addressVal.decAddress = $1;
}
| LABEL
{
//对于标号地址,应当先到标号表中查询看有无对应项,如果有的话,就应当
//将查询到的地址放入g_eaAddressVal中
//如果没有的话,就应当在标号表的指定标号中
//加入一个回填项以便于在parse过程中如果遇到了指定的标号
//进行标号数据的回填
g_currentEAAddress.type = LABEL_EA_ADDRESS;
strcpy(g_currentEAAddress.addressVal.labelAddress.strLabelName, (char*)$1);
free((char*)$1);
}
| HEX
{
//-----------------有效地址也可以有十六进制数!!!!!----------------------
//unfinished now!!
//因为在使用的时候,我们不需要去理会十六进制与十进制的区别,因为词法分析模块已经替我们
//将十六进制的输入换为十进制的数据了!!!!所以我们直接将HEX的地址量当DEC来用即可!!!
//-----------------------------------------------------------------
g_currentEAAddress.type = DEC_EA_ADDRESS;
g_currentEAAddress.addressVal.decAddress = $1;
}
;
XRADDR: ','XR
{
//g_iCurrentEARegNumber = g_iCurrentRegNumber;
}
|
{
g_iCurrentEARegNumber = REG_EMPTY;
}
;
XR: GR0
{
g_iCurrentEARegNumber = 0;
}
| GR1
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -