111 lines
3.5 KiB
C
111 lines
3.5 KiB
C
// 简单逻辑表达式求值:支持 true/false 与 not/and/or,带错误检测
|
|
// 规则:
|
|
// - 仅包含单词 true, false, not, and, or 与空格;全部小写
|
|
// - 优先级:not > and > or;同级从左到右(左结合)
|
|
// - 输入为一行,输出为 true / false;如果语法或词法错误,输出 error
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
|
|
typedef enum { TK_TRUE, TK_FALSE, TK_AND, TK_OR, TK_NOT } Tok;
|
|
|
|
// 读取一行到缓冲区,并去除尾部换行符
|
|
static int read_line(char *buf, size_t sz) {
|
|
if (!fgets(buf, (int)sz, stdin)) return 0;
|
|
size_t n = strlen(buf);
|
|
while (n && (buf[n-1] == '\n' || buf[n-1] == '\r')) buf[--n] = '\0';
|
|
return 1;
|
|
}
|
|
|
|
// 词法:按字母分组,提取单词,映射到令牌;出错返回 -1
|
|
static int tokenize(const char *s, Tok *out, int maxn) {
|
|
int nt = 0;
|
|
size_t i = 0, n = strlen(s);
|
|
while (i < n) {
|
|
while (i < n && isspace((unsigned char)s[i])) ++i;
|
|
if (i >= n) break;
|
|
if (!isalpha((unsigned char)s[i])) return -1; // 非法字符
|
|
size_t j = i;
|
|
while (j < n && isalpha((unsigned char)s[j])) ++j;
|
|
size_t wlen = j - i;
|
|
if (wlen == 4 && strncmp(s + i, "true", 4) == 0) {
|
|
if (nt >= maxn) return -1;
|
|
out[nt++] = TK_TRUE;
|
|
} else if (wlen == 5 && strncmp(s + i, "false", 5) == 0) {
|
|
if (nt >= maxn) return -1;
|
|
out[nt++] = TK_FALSE;
|
|
} else if (wlen == 3 && strncmp(s + i, "and", 3) == 0) {
|
|
if (nt >= maxn) return -1;
|
|
out[nt++] = TK_AND;
|
|
} else if (wlen == 2 && strncmp(s + i, "or", 2) == 0) {
|
|
if (nt >= maxn) return -1;
|
|
out[nt++] = TK_OR;
|
|
} else if (wlen == 3 && strncmp(s + i, "not", 3) == 0) {
|
|
if (nt >= maxn) return -1;
|
|
out[nt++] = TK_NOT;
|
|
} else {
|
|
return -1; // 未知单词
|
|
}
|
|
i = j;
|
|
}
|
|
return nt;
|
|
}
|
|
|
|
// 递归下降(迭代实现)语法:
|
|
// unary := { not }* ( true | false )
|
|
// and := unary { and unary }*
|
|
// or := and { or and }*
|
|
|
|
static int parse_unary(const Tok *toks, int nt, int *idx, int *ok) {
|
|
int neg = 0;
|
|
while (*idx < nt && toks[*idx] == TK_NOT) { ++neg; ++*idx; }
|
|
if (*idx >= nt) { *ok = 0; return 0; }
|
|
int val;
|
|
if (toks[*idx] == TK_TRUE) { val = 1; }
|
|
else if (toks[*idx] == TK_FALSE) { val = 0; }
|
|
else { *ok = 0; return 0; }
|
|
++*idx;
|
|
if (neg & 1) val = !val;
|
|
return val;
|
|
}
|
|
|
|
static int parse_and(const Tok *toks, int nt, int *idx, int *ok) {
|
|
int lhs = parse_unary(toks, nt, idx, ok);
|
|
if (!*ok) return 0;
|
|
while (*idx < nt && toks[*idx] == TK_AND) {
|
|
++*idx;
|
|
int rhs = parse_unary(toks, nt, idx, ok);
|
|
if (!*ok) return 0;
|
|
lhs = (lhs && rhs);
|
|
}
|
|
return lhs;
|
|
}
|
|
|
|
static int parse_or(const Tok *toks, int nt, int *idx, int *ok) {
|
|
int lhs = parse_and(toks, nt, idx, ok);
|
|
if (!*ok) return 0;
|
|
while (*idx < nt && toks[*idx] == TK_OR) {
|
|
++*idx;
|
|
int rhs = parse_and(toks, nt, idx, ok);
|
|
if (!*ok) return 0;
|
|
lhs = (lhs || rhs);
|
|
}
|
|
return lhs;
|
|
}
|
|
|
|
int main(void) {
|
|
char line[512];
|
|
if (!read_line(line, sizeof(line))) return 0;
|
|
|
|
Tok toks[300];
|
|
int nt = tokenize(line, toks, 300);
|
|
if (nt <= 0) { printf("error\n"); return 0; }
|
|
|
|
int idx = 0, ok = 1;
|
|
int result = parse_or(toks, nt, &idx, &ok);
|
|
if (!ok || idx != nt) { printf("error\n"); return 0; }
|
|
|
|
printf(result ? "true\n" : "false\n");
|
|
return 0;
|
|
} |