MiniBasic解析器实现

前几天朋友需要,帮忙做了一个类似Basic的解析器,就当是练练手吧。它给的题目如下:

编写一个MiniBasic语言的解释程序,对于任何一个给出的正确的MiniBasic语言的程序,你的程序能运行它并得到正确的结果。那么,怎样的MiniBasic的程序叫做正确的呢?

1)符合MiniBasic语言的语法规则;

2)程序执行时会产生一个或多个输出,可以中断(即程序不会进入无限循环状态)。 MiniBasic语言的语法规则:

1)每一行的MiniBasic程序都是下面这样的形式(所有出现的字母均为大写)

 [<空格>]<行号><空格><语句>

其中,

[<空格>]中可以有任意个空格,当然也可以没有;

 <行号>中一定要有行号,从1开始,依次递增1

 <空格>中至少有一个空格;

<语句>应为下面的语句之一:

      LET<空格><变量>=<表达式>

PRINT<空格><变量>

IF<空格><表达式>

GOTO<空格><表达式>

      STOP

2)定义变量和表达式的规则为

<变量>必须是单个的大写英文字母,存储一个整数值;

<表达式>  

<常量>     范围在[-10000…10000]内的整数常量,比如0-534  

<变量>+<变量> 两个变量所代表的是有符号整数  

<变量>><变量> 大于号,真为1,假为0

3)表达式中和LET语句的=(等号)两边没有空格;

4TinyBasic的程序最多只有100行。

执行TinyBasic语言程序的规则:

1)从程序中的第1行开始执行;

2)程序中用到的所有变量的初始值均为0

3)语句连续执行除非碰到IFGOTO语句;

45种语句的定义  

LET   给变量赋值。若两个变量相加,相加的结果在[-10000…10000]之内。  

PRINT <变量名>=<>的格式打印变量的值。左对齐,并单独占用一行;行中无任何多余空格。 

      GOTO 跳到行号为<表达式>的值的一行。<表达式>不需要是一个常量;<表达式>的值是程序中的有效行号。 

      IF     如果表达式的值非0继续执行下一行;如果表达式的值为0跳过下一行,执行下一行的下一行。在IF语句以下至少还应该有两条语句。  

STOP   终止执行。MiniBasic程序一定会执行到STOP语句(如果你的解释程序是正确的话);MiniBasic程序可能包含一个以上的STOP语句;程序的最后一句不一定是STOP语句。

输入格式

输入数据只有一组,包含一个程序,没有多余的空行,每一行为一条语句,具体要求按上面的解释。你编写的程序要正确地运行该MiniBasic程序。

输出格式

输出程序的运行结果,文件头尾都不需要多余空行。

示例输入

1 LET A=10

2 LET I=0

3 LET X=I+I

4 LET T=1

5 LET X=X+T

6 PRINT X

7 LET T=1

8 LET I=I+T

9 IF A>I

10 GOTO 3

11 STOP

示例输出

X=1

X=3

X=5

X=7

X=9

X=11

X=13

X=15

X=17

X=19

 

设计要求:

 

给出能实现上述功能的设计方案和实现模块

 

这里为了考虑它的扩展性,我将它封装到一个C++的类中了,这样的话,以后要扩展其它指令或者支持更多的变量,都可以轻松实现。现将C++头文件列出如下:

#ifndef _LINENODE_H
#define _LINENODE_H

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

enum CommmandType
{
   ELET=0,    /*赋值语句*/
   EPRINT,  /*打印*/
   EGOTO,  /*跳转*/  /* goto 变量, 此时,变量的索引存在ResultValue中*/
   EIF,   /*判断语句*/   /*大于,IF  X>Y    X:LeftValue   Y:RightValue      */  
   ESTOP, /*停止执行*/
   EUnKnown/*未知,错误指令*/
};

enum OperatorType
{
   ESet=0,    /*赋值,LET X=Y    X:ResultValue Y:LeftValue  */
   EAdd,      /*相加,LET X=Y+Z  X:ResultValue Y:LeftValue Z:RightValue */
};

typedef struct _Var
{
  int is_const; //是否常量 1是,0不是
  int value;    //is_const=1时,value为该常量的值,否则为变量的索引
}Var;


typedef struct _LNode
{
     int LineNumber;
 CommmandType CType;    /*命令类型*/
 OperatorType OType;    /*当前表达式的操作符类型*/
 Var  LeftValue;       /*表达式操作符左边的值的下标*/
 Var  RightValue;      /*表达式操作符右边的值*/
 Var  ResultValue;     /*当使用Let语句时,保存为等号左边的值的下标*/  
 char Commands[2048];  /*输入的指令*/
 struct _LNode *prior;
 struct _LNode *next;
}LNode,*pLNode;

#define BLANK_CHAR    0x20
#define VAR_ARRY_MAX  26
#define IS_CONST_CHAR(ch) (ch=='-'||(ch>='0'&&ch<='9'))     

class LineNode
{
private:
 int m_auto_number; //是否自动输出行号
 int m_auto_line_number; //自动输出的行号
 pLNode pHead; //头指针
 char sInputBuffer[2048];
 int  Var_Values[VAR_ARRY_MAX];   //变量数组 X-Z总共26个字母变量

 int ParseLineNumber(const char *sBuffer,int *endPos); //解释当前行号
 CommmandType ParseCommand(const char *sBuffer,int *endPos); //解析当前的命令
 void ParseExpression(char *sBuffer,int *endPos,pLNode pNode);  //解析表达式
 int PosChar(const char *sBuffer,char ch);   //返回 指定符号的位置,如果返回0表未找不到指定符号
 int GetValue(Var *var);  //取变量的值
 void SetValue(Var *var,int value); //设置变量的值
 bool LocalInput(const char *sBuf);  //直接解析字符串
 
 int ReadLine(FILE  *fp, char *lineBuffer, int maxLength);//从文件中读取一行

 CommmandType ParseInput(char *sBuffer);  //解析一条指令
public:
 LineNode(int auto_number=1);
 ~LineNode();

 void  SetAutoNumber(int auto_number=1);
 bool  ExpressionResult(Var *leftVar,Var *rightVar);
 void  PrintResult(Var *var,FILE *fp=NULL);
 pLNode GotoLine(Var *var);
    pLNode AllocNode();
 bool Input();
 void Caculate();
 void Clear();
 void PrintCommands(FILE *fp=NULL);

 void LoadCommandFromFile(const char *sFileName);
 void SaveCommandToFile(const char *sFileName);
};

#endif

 

运行效果如图所示:http://hi.csdn.net/attachment/201012/3/0_1291359764Ag2j.gif

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值