用自动状态变迁图方案从表达式中取出运算数
问题:
从键盘输入一个包含数字字符的字符串,从中取出符合双精度常量格式的数字字符串,并将其转换成数值常量。
问题起因源于:要对一个表达式进行分析,发现可能存在的错误,若无错误,则进行表达式运算;想要解决该问题:首先得解决其中明显的技术性问题:括号匹配和从字符串中取数字字符串并转换成真正的数值常量。括号匹配在上一篇博文中已解决,在该篇中解决如何从字符串中取出符合双精度常量要求的字符串。
思路:
1.双精度常量由 正号、负号、小数点、数值组成。
2.结合实际思考:如 34 3.4 -1.2 .3 3. 0. 都符合双精度常量格式;而 -. +. . 不符合双精度常量格式。
3.双精度常量刚开始可以是:
(1)符号: +,- ;(2)数值 (3)小数点 .
如12.34.5 计算机能够正确取出12.34 和 .5 两个符合双精度格式的数值;但目前所编程序只能取出第一个正确的数值,12.34;
了解了双精度常量格式后,给出一种高级方案:
自动状态变迁图描述双精度常量格式且自动状态变迁图具有两种稳定状态: 开始状态 结束状态;
得到自动状态变迁图如下:
根据自动状态变迁图编写代码如下:
c代码:
#include <stdio.h>
#include <ctype.h>
#include "glrError.h"
#define NUMBER_START_STATUS 1
#define NUMBER_INT_STATUS 2
#define NUMBER_SIGN_STATUS 3
#define NUMBER_DOT_STATUS 4
#define NUMBER_DEC_STATUS 5
#define NUMBER_END_STATUS 6
typedef unsigned char boolean;
#define TRUE 1
#define FALSE 0
typedef struct ARG{
int index;
int status;
boolean ok;
boolean finished;
double values;
int sign;
double dec;
}ARG;
extern const char *errMess;
boolean getNumber(const char *str,int *count,double *result);
boolean isSign(int ch);
void dealStartStatus(int ch,ARG *arg);
void dealIntStatus(int ch,ARG *arg);
void dealSignStatus(int ch,ARG *arg);
void dealDotStatus(int ch,ARG *arg);
void dealDecStatus(int ch,ARG *arg);
void processInt(int ch,ARG *arg);
void processSign(int ch,ARG *arg);
void processDot(int ch,ARG *arg);
void processDec(int ch,ARG *arg);
void processDec(int ch,ARG *arg) {
arg->values += arg->dec * (ch - '0');
arg->dec/=10.0;
}
void processDot(int ch,ARG *arg) {
arg->dec = 0.1;
}
void processSign(int ch,ARG *arg) {
arg->sign = ('-' == ch ? -1 : 1);
}
void processInt(int ch,ARG *arg) {
arg->values = arg->values*10.0 + (ch - '0');
}
void dealDecStatus(int ch,ARG *arg) {
if(isdigit(ch)){
processDec(ch,arg);
arg->status = NUMBER_DEC_STATUS;
arg->index++;
}else {
arg->status = NUMBER_END_STATUS;
}
}
void dealDotStatus(int ch,ARG *arg) {
if(isdigit(ch)){
processDec(ch,arg);
arg->status = NUMBER_DEC_STATUS;
arg->index++;
}else {
errMess = "不能只出现小数点!\n";
arg->ok = FALSE;
}
}
void dealSignStatus(int ch,ARG *arg) {
if(isdigit(ch)){
processInt(ch,arg);
arg->status = NUMBER_INT_STATUS;
arg->index++;
}else if('.' == ch){
processDot(ch,arg);
arg->status = NUMBER_DOT_STATUS;
arg->index++;
}else {
errMess = "不可识别字符!\n";
arg->ok = FALSE;
}
}
void dealIntStatus(int ch,ARG *arg) {
if(isdigit(ch)){
processInt(ch,arg);
arg->status = NUMBER_INT_STATUS;
arg->index++;
}else if('.' == ch){
processDot(ch,arg);
arg->status = NUMBER_DEC_STATUS;
arg->index++;
}else {
arg->status = NUMBER_END_STATUS;
}
}
boolean isSign(int ch) {
return '+' == ch || '-' == ch;
}
void dealStartStatus(int ch,ARG *arg) {
if(isdigit(ch)){
processInt(ch,arg);
arg->status = NUMBER_INT_STATUS;
arg->index++;
}else if(isSign(ch)){
processSign(ch,arg);
arg->status = NUMBER_SIGN_STATUS;
arg->index++;
}else if('.' == ch){
processDot(ch,arg);
arg->status = NUMBER_DOT_STATUS;
arg->index++;
}else{
errMess = "出师未捷身先死!\n";
arg->ok = FALSE;
}
}
boolean getNumber(const char *str,int *count,double *result) {
ARG arg = {
0, //index
NUMBER_START_STATUS, //status
TRUE, //ok
FALSE, //finished
0.0, //values
1, //sign
0.0, //dec
};
int ch;
while(arg.ok && !arg.finished) {
ch = str[arg.index];
if(NUMBER_START_STATUS == arg.status){
dealStartStatus(ch,&arg);
}else if(NUMBER_INT_STATUS == arg.status){
dealIntStatus(ch,&arg);
}else if(NUMBER_SIGN_STATUS == arg.status){
dealSignStatus(ch,&arg);
}else if(NUMBER_DOT_STATUS == arg.status){
dealDotStatus(ch,&arg);
}else if(NUMBER_DEC_STATUS == arg.status){
dealDecStatus(ch,&arg);
}else if(NUMBER_END_STATUS == arg.status){
*count += arg.index;
*result = arg.values * arg.sign;
arg.finished = TRUE;
}
}
return arg.ok;
}
int main(){
char str[80];
boolean ok;
int index = 0;
double values = 0.0;
printf("Input the str:");
gets(str);
ok = getNumber(str,&index,&values);
if(ok) {
printf("%lf\n",values);
index++;
ok = getNumber(str+index,&index,&values);
if(ok){
printf("%lf\n",values);
}else{
showError();
}
}else{
showError();
}
return 0;
}
专门针对错误给出一套错误处理机制,这里需要glrError.h和glrError.c文件支持,代码如下:
glrError.h文件:
#ifndef _GLR_ERROR_H_
#define _GLR_ERROR_H_
void showError();
#endif
glrError.c文件:
#include <stdio.h>
#include "glrError.h"
const char *errMess = NULL;
void showError(){
if(NULL == errMess) {
return;
}else{
printf("%s\n",errMess);
}
}
最后连编得到结果如下:
结果:
输入:-3.14+.
输出:-3.140000
不能只出现小数点!