C语言自制计算器

自制计算器

功能介绍

  • 实现+、-、*、/、( )、负数运算

涉及功能

  • 自制词法分析器
  • 自制语法分析器

实现情况

程序框架

代码实现

词法分析器

/*************************************************************************
	> Description:自制词法分析器 
 ************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "token.h"

static char *st_line;
static int st_line_pos;

/*存储数值特征*/
typedef enum {
    INITIAL_STATUS,//初始化状态
    IN_INT_PART_STATUS,//遇到整数
    DOT_STATUS,//遇到小数点
    IN_FRAC_PART_STATUS//再遇到整数
} LexerStatus;

void get_token(Token *token) {
    int out_pos = 0;
    LexerStatus status = INITIAL_STATUS;
    char current_char;

    token->kind = BAD_TOKEN;
    while (st_line[st_line_pos] != '\0') {
        current_char = st_line[st_line_pos];
        if ((status == IN_INT_PART_STATUS || status == IN_FRAC_PART_STATUS) && !isdigit(current_char) && current_char != '.') {
            token->kind = NUMBER_TOKEN;
            sscanf(token->str, "%lf", &token->value);
            return;
        }
        if (isspace(current_char)) {
            if (current_char == '\n') {
                token->kind = END_OF_LINE_TOKEN;
                return;
            }
            st_line_pos++;
            continue;
        }

        if (out_pos >= MAX_TOKEN_SIZE - 1) {
            fprintf(stderr, "token too long.\n");
            exit(1);
        }
        token->str[out_pos] = st_line[st_line_pos];
        st_line_pos++;
        out_pos++;
        token->str[out_pos] = '\0';

        if (current_char == '+') {
            token->kind = ADD_OPERATOR_TOKEN;
            return;
        } else if (current_char == '-') {
            token->kind = SUB_OPERATOR_TOKEN;
            return;
        } else if (current_char == '*') {
            token->kind = MUL_OPERATOR_TOKEN;
            return;
        } else if (current_char == '/') {
            token->kind = DIV_OPERATOR_TOKEN;
            return;
        } else if (current_char == '(') {
            token->kind = LEFT_PAREN_TOKEN;
            return;
        } else if (current_char == ')') {
            token->kind = RIGHT_PAREN_TOKEN;
            return;
        } else if (isdigit(current_char)) {
            if (status == INITIAL_STATUS) {
                status = IN_INT_PART_STATUS;
            } else if (status == DOT_STATUS) {
                status = IN_FRAC_PART_STATUS;
            }
        } else if (current_char == '.') {
            if (status == IN_INT_PART_STATUS) {
                status = DOT_STATUS;
            } else {
                fprintf(stderr, "syntax error.\n");
                exit(1);
            }
        }
    }
}

void set_line(char *line) {
    st_line = line;
    st_line_pos = 0;
}

#if 0
void
parse_line(void) {
    Token token;
    st_line_pos = 0;

    for (;;) {
        get_token(&token);
        if (token.kind == END_OF_LINE_TOKEN) {
          break;
        } else {
            printf("kind..%d, str..%s\n", token.kind, token.str);
        }
    }
}

int main(int argc, char **argv) {
    while (fgets(st_line, LINE_BUF_SIZE, stdin) != NULL) {
        parse_line();
    }

    return 0;
}
#endif

语法分析器

/*************************************************************************
    > Description:自制语法分析器
 ************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include "token.h"

#define LINE_BUF_SIZE (1024)

static Token st_look_ahead_token;
static int st_look_ahead_token_exists;

static void my_get_token(Token *token) {
    if (st_look_ahead_token_exists) {
        *token = st_look_ahead_token;
        st_look_ahead_token_exists = 0;
    } else {
        get_token(token);
    }
}

static void unget_token(Token *token) {
    st_look_ahead_token = *token;
    st_look_ahead_token_exists = 1;
}

double parse_expression(void);

static double parse_primary_expression() {
    Token token;
    double value = 0.0;
    int minus_flag = 0;

    my_get_token(&token);
    if (token.kind == SUB_OPERATOR_TOKEN) {
        minus_flag = 1;
    } else {
        unget_token(&token);
    }

    my_get_token(&token);
    if (token.kind == NUMBER_TOKEN) {
        value = token.value;
    } else if (token.kind == LEFT_PAREN_TOKEN) {
        value = parse_expression();
        my_get_token(&token);
        if (token.kind != RIGHT_PAREN_TOKEN) {
            fprintf(stderr, "missing ')' error.\n");
            exit(1);
        }
    } else {
        unget_token(&token);
    }
    if (minus_flag) {
        value = -value;
    }
    return value;
}

static double parse_term() {
    double v1;
    double v2;
    Token token;

    v1 = parse_primary_expression();
    for (;;) {
        my_get_token(&token);
        if (token.kind != MUL_OPERATOR_TOKEN && token.kind != DIV_OPERATOR_TOKEN) {
            unget_token(&token);
            break;
        }
        v2 = parse_primary_expression();
        if (token.kind == MUL_OPERATOR_TOKEN) {
            v1 *= v2;
        } else if (token.kind == DIV_OPERATOR_TOKEN) {
            v1 /= v2;
        }
    }
    return v1;
}

double parse_expression() {
    double v1;
    double v2;
    Token token;

    v1 = parse_term();
    for (;;) {
        my_get_token(&token);
        if (token.kind != ADD_OPERATOR_TOKEN && token.kind != SUB_OPERATOR_TOKEN) {
            unget_token(&token);
            break;
        }
        v2 = parse_term();
        if (token.kind == ADD_OPERATOR_TOKEN) {
            v1 += v2;
        } else if (token.kind == SUB_OPERATOR_TOKEN) {
            v1 -= v2;
        } else {
            unget_token(&token);
        }
    }
    return v1;
}

double parse_line(void) {
    double value;

    st_look_ahead_token_exists = 0;
    value = parse_expression();

    return value;
}

int main(int argc, char **argv) {
    char line[LINE_BUF_SIZE];
    double value;

    while (fgets(line, LINE_BUF_SIZE, stdin) != NULL) {
        set_line(line);
        value = parse_line();
        printf(">>%f\n", value);
    }

    return 0;
}

头文件

#ifndef INCLUDE_H_INCLUDED
#define INCLUDE_H_INCLUDED

//枚举记号种类状态
typedef enum {
    BAD_TOKEN, //错误记号
    NUMBER_TOKEN, //数字记号
    ADD_OPERATOR_TOKEN, //‘+’记号
    SUB_OPERATOR_TOKEN, //‘-’记号
    MUL_OPERATOR_TOKEN, //‘*’记号
    DIV_OPERATOR_TOKEN, //‘/’记号
    LEFT_PAREN_TOKEN,   //‘(’记号
    RIGHT_PAREN_TOKEN,  //‘)’记号
    END_OF_LINE_TOKEN   //结束记号
} TokenKind;

#define MAX_TOKEN_SIZE (100)

typedef struct {
    TokenKind kind;//记录记号
    double value;//记录数值
    char str[MAX_TOKEN_SIZE];//记录运算符
} Token;

/* 将接下来要解析的行置入词法分析器中 */
void set_line(char *line);

/* 从被置入的行中,分割记号并返回
* 在行尾会返回 END_OF_LINE_TOKEN 这种特殊的记号
* 接受的入口参数为一个 Token 结构体指针
* 函数中会分割出 记号的信息装入 Token 结构体并返回*/
void get_token(Token *token);

#endif /* INCLUDE_H_INCLUDED */

makefile

CC = gcc
CFLAGS = -Wall -g -D _DEBUG 
OBJS = parser.o lexer.o

.PHONY: clean

./a.out : $(OBJS)
	$(CC) $(CFLAGS) $(OBJS) -o mycalc 

parser.o : parser.c token.h
	$(CC) -c $(CFLAGS) parser.c

lexer.o : lexer.c token.h 
	$(CC) -c $(CFLAGS) lexer.c 

clean:
	rm -rf *.o mycalc
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
C语言高级计算器编程是使用C语言编写一个功能强大的计算器程序。计算器是一个常用工具,但是普通的计算器功能有限,而高级计算器则可以拓展更多的功能,提供更便捷的计算服务。 在编写C语言高级计算器时,我们可以利用C语言的特性和库函数来实现各种高级功能,比如支持多种数学运算、支持复数计算、支持变量定义和使用、支持函数调用、支持逻辑运算和条件判断、支持循环控制等等。 通过使用C语言计算器程序,可以方便地进行各种数学计算,比如四则运算、求平方根、求幂运算等。同时,还可以支持更高级的数学运算,如三角函数、对数运算、阶乘运算等。 除了数学运算,C语言高级计算器还可以支持变量定义和使用,可以通过定义变量来储存中间计算结果,以便在后续计算中使用。同时,还可以支持函数调用,用户可以自定义函数,并在计算过程中调用这些函数进行特定的计算。 此外,C语言高级计算器还可以支持逻辑运算和条件判断,用户可以进行条件判断来确定计算的进程和结果。同时,还可以支持循环控制,用户可以编写循环结构来进行重复计算或迭代计算。 总之,C语言高级计算器编程是一项有挑战性和实用性的任务,在编写过程中需要理解和运用C语言的各种特性和库函数,以实现一个功能强大的计算器程序。通过这样的高级计算器,可以实现更多的数学运算和功能,提供更便捷的计算服务。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值