首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C >> 關於C

C語言實現四則運算計算器:遞歸下降解析器

     編輯:關於C

從整數到浮點數的計算器演進

基於《編譯原理及實踐》中的整數計算器,擴展支持:

  1. 浮點數運算(double 類型)
  2. 除法運算(/)
  3. 空白字符跳過

運行效果演示

計算器運行截圖

核心代碼實現

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

char token;  // 當前 token

double exp(void);   // 處理加減
double term(void);  // 處理乘除
double factor(void); // 處理括號和數字

// 獲取下一個可打印字符(跳過空白)
char getPrintableChar(void) {
    char temp;
    do temp = getchar(); while (isblank(temp));
    return temp;
}

// 匹配期望字符,不匹配報錯
void match(char expectedToken) {
    if (expectedToken == token) token = getPrintableChar();
    else { fprintf(stderr, "Error!\n"); exit(EXIT_FAILURE); }
}

// 表達式:exp → term { (+|-) term }
double exp(void) {
    double temp = term();
    while (token == '+' || token == '-') {
        switch (token) {
            case '+': match('+'); temp += term(); break;
            case '-': match('-'); temp -= term(); break;
        }
    }
    return temp;
}

// 項:term → factor { (*|/) factor }
double term(void) {
    double temp = factor();
    while (token == '*' || token == '/') {
        switch (token) {
            case '*': match('*'); temp *= factor(); break;
            case '/': match('/'); temp /= factor(); break;
        }
    }
    return temp;
}

// 因子:factor → ( exp ) | Number
double factor(void) {
    double temp;
    if (token == '(') {
        match('('); temp = exp(); match(')');
    } else if (isdigit(token)) {
        ungetc(token, stdin);  // 退回去讓 scanf 讀完整浮點數
        scanf("%lf", &temp);
        token = getPrintableChar();
    } else {
        fprintf(stderr, "Error!\n"); exit(EXIT_FAILURE);
    }
    return temp;
}

int main(void) {
    double result;
    for (;;) {
        token = getPrintableChar();
        if (token == 'q') break;  // 輸入 q 退出
        result = exp();
        if (token == '\n') printf("Result is: %g\n", result);
        else { fprintf(stderr, "Error!\n"); exit(EXIT_FAILURE); }
    }
    return 0;
}

文法對應關係(EBNF)

<exp>   → <term> { (+|-) <term> }
<term>  → <factor> { (*|/) <factor> }
<factor> → ( <exp> ) | Number
  • exp() 對應 <exp>,處理最低優先級(加減)
  • term() 對應 <term>,處理中等優先級(乘除)
  • factor() 對應 <factor>,處理最高優先級(括號、數字)

關鍵技術點解析

1. 遞歸下降解析

每個非終結符對應一個函數,函數調用鏈直接映射文法推導過程。代碼結構清晰,易於擴展(如添加乘方、函數調用)。

2. Token 流處理

  • getPrintableChar():詞法分析器,跳過空白字符
  • match():語法分析器核心,驗證並消費 token
  • 全局 token 充當「向前看一個符號」的緩衝

3. 數字識別技巧

ungetc(token, stdin);  // 把已讀的首位數字退回流
scanf("%lf", &temp);    // 讓 scanf 完整讀取浮點數

避免手寫浮點數解析邏輯,利用標準庫優勢。

4. 錯誤處理

統一使用 error() 輸出錯誤並退出,簡單直接。生產環境可改為拋出異常或返回錯誤碼。

擴展建議

  • 添加負數支持:在 factor() 中處理一元 -
  • 支持變量:引入符號表,factor() 識別標識符查表
  • 錯誤恢復:遇錯跳過到下一行而非直接退出
  • 編譯為 AST:構建抽象語法樹,分離解析與求值
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved