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

C語言科學計算器完整實現:表達式解析、中綴轉後綴、棧式計算、錯誤處理與交互循環

     編輯:C 語言入門

項目能力清單

  • ✅ 四則運算 + 乘方(`^`)
  • ✅ 三角函數:sin/cos/tan/asin/acos/atan(弧度制)
  • ✅ 指對數:ln/log10
  • ✅ 常數:e、pi
  • ✅ 括號任意嵌套、優先級正確
  • ✅ 智能忽略空格
  • ✅ 錯誤檢測:除零、定義域溢出、括號不匹配、非法字符
  • ✅ 交互功能:連續計算、清屏(`c`)、退出(`q`)

核心算法:中綴表達式 → 後綴(逆波蘭) → 棧計算

1. 詞法分析

掃描輸入字符串,識別 Token:

  • 操作數:數字(整數/小數)、`e`、`pi`
  • 運算符:`+ - * / ^ ( ) =`
  • 函數名:`sin cos tan asin acos atan ln lg`(單字符編碼:`s c t a+s a+c a+t n g`)

2. 語法分析:遞歸下降 / 算符優先(本項採用算符優先 + 隱式遞歸處理括號)

// 運算符優先級
int precedence(char op) {
    switch(op) {
        case '+': case '-': case '=': case ')': return 1;
        case '*': case '/': return 2;
        case '^': return 3;
        default: return 0; // 函數、'('
    }
}

// 核心計算引擎:雙棧法(操作數棧 OPRD、運算符棧 OPRT)
double calculate(Node *tokens) {
    double OPRD[200]; int top_oprd = 0;
    char OPRT[200]; int top_oprt = 0;
    // 處理一元負號:表達式首或 ( 後的 -,壓入 0 作為左操作數
    // 主循環:讀 Token
    //   操作數 → 壓 OPRD
    //   運算符 → 
    //      若 OPRT 為空或棧頂優先級 < 當前 → 壓 OPRT
    //      若棧頂優先級 ≥ 當前 → 彈出計算(雙目/單目),結果壓回 OPRD
    //   左括號 → 壓 OPRT,遞歸計算括號內表達式
    //   右括號/= → 彈出計算至匹配左括號/棧底
    // 最終 OPRD[0] 為結果
}

3. 單目/雙目運算分發


// 單目:sin/cos/tan/asin/acos/atan/ln/lg
int single_op(char op, double *x) {
    switch(op) {
        case 's': *x = sin(*x); break;
        case 'c': *x = cos(*x); break;
        case 't': *x = tan(*x); break;
        case 'a'+'s': if(*x<-1||*x>1) return 0; *x=asin(*x); break;
        case 'a'+'c': if(*x<-1||*x>1) return 0; *x=acos(*x); break;
        case 'a'+'t': if(*x<-M_PI_2||*x>M_PI_2) return 0; *x=atan(*x); break;
        case 'n': if(*x<=0) return 0; *x=log(*x); break;
        case 'g': if(*x<=0) return 0; *x=log10(*x); break;
    }
    return 1;
}

// 雙目:+ - * / ^
int double_op(char op, double *a, double b) {
    switch(op) {
        case '+': *a += b; break;
        case '-': *a -= b; break;
        case '*': *a *= b; break;
        case '/': if(fabs(b)<1e-8) return 0; *a /= b; break;
        case '^': *a = pow(*a, b); break;
    }
    return 1;
}

關鍵數據結構

typedef enum { Opd=0, Opt=1 } Type;
typedef struct {
    int opt;      // 運算符編碼
    double opd;   // 操作數值
    Type tp;      // 類型標記
} Node;           // 表達式 Token 鏈節點

// 輸入緩衝區
char input_buf[1000];
Node tokens[500];

交互主循環

int main() {
    while (1) {
        // 1. 清空狀態
        memset(tokens, 0, sizeof(tokens));
        bracket_stack_clear();
        
        // 2. 輸入
        printf("Enter: ");
        if (!read_and_tokenize(tokens)) { puts("Input Error!"); continue; }
        
        // 3. 計算
        double result;
        if (calculate(tokens, &result)) {
            if (bracket_mismatch) { puts("Bracket mismatch!"); continue; }
            // 4. 輸出:整數顯示無小數,浮點保留 4 位
            if (floor(result) == result) printf("%d\n", (int)result);
            else printf("%.4f\n", result);
        }
        
        // 5. 命令處理
        int c = getchar();
        if (c == 'q') break;
        else if (c == 'c') system("clear"); // Windows 用 "cls"
        if (c != '\n') getchar(); // 吞換行
    }
    puts("Quit...");
}

編譯與運行

gcc calc.c -o calc -lm -std=c99
# Windows MSVC
cl calc.c /link /subsystem:console
# 運行
./calc
Enter: 2+3*4
14
Enter: sin(pi/2)
1
Enter: 2^10
1024
Enter: q
Quit...

代碼亮點與可擴展點

模塊亮點擴展方向
詞法分析統一 `translate()` 分發,`translateopd()` 處理小數、`e`、`pi`支持十六進制、變量賦值(`x=2`)
語法分析算符優先 + 遞歸處理括號,單/雙目統一框架引入 Shunting Yard 算法生成顯式後綴,支持更多運算符
錯誤處理定義域檢查、除零、括號匹配、非法字符錯誤位置報告、恢復策略
交互非阻塞 `getch()` 實現 ESC 切換(客戶端代碼),主循環命令歷史記錄(上下鍵)、變量存儲、腳本模式

總結

這是一個教學級工業強度的 C 語言表達式計算器:無外部依賴(僅標準庫),手寫詞法/語法/語義全流程,展示了編譯器前端核心技術在微型項目中的完整應用。代碼結構清晰,擴展性強,極適合作為編譯原理實踐、數據結構棧應用、C 語言綜合訓練的參考項目。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved