プロが教える店舗&オフィスのセキュリティ対策術

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

#define BUFFERSIZE 1024
char Buffer[BUFFERSIZE];
int Index;
int ParseError;

int getE(void);

void parseError(FILE *out, char msg[]) {
ParseError = 1;
fprintf(out, "%s\n", msg);
fprintf(out, "%s\n", Buffer);
for (int i = 0; i < Index; i++) fprintf(out, " ");
fprintf(out, "^\n");
}

void removeWhite(void) {
int j = 0, c;
for (int i = 0; (c = Buffer[i]) != '\0'; i++) {
if (c == ' ' || c == '\t' || c == '\n') continue;
Buffer[j++] = c;
}
Buffer[j] = '\0';
}

int getD(void) {
int value = 0;
while (isdigit(Buffer[Index])) {
value = 10*value + Buffer[Index] - '0';
Index++;
}
return value;
}

int getF(void) {
int value;
if (isdigit(Buffer[Index])) { // 数値表現
value = getD(); if (ParseError) return 0;
} else if (Buffer[Index] == '(') { // ( E )
++Index;
value = getE(); if (ParseError) return 0;
if (Buffer[Index] == ')') {
++Index;
} else {
parseError(stderr, "閉じ括弧')'がありません."); return 0;
}
} else {
parseError(stderr, "数字または開き括弧'('がありません."); return 0;
}
return value;
}

int getT(void) {
int v, value;
value = getF(); if (ParseError) return 0;
while (Buffer[Index] == '*' || Buffer[Index] == '/') {
char op = Buffer[Index++];
v = getF(); if (ParseError) return 0;
if (op == '*') value *= v; else value /= v;
}
return value;
}

int getE(void) {
int v, value;
if (Buffer[Index] == '-') {
++Index;
v = getT(); if (ParseError) return 0;
value = -v;
} else {
value = getT(); if (ParseError) return 0;
}
while (Buffer[Index] == '+' || Buffer[Index] == '-') {
char op = Buffer[Index++];
v = getT(); if (ParseError) return 0;
if (op == '+') value += v; else value -= v;
}
return value;
}

int getExpression(void) {
int value;
value = getE(); if (ParseError) return 0;
if (Buffer[Index] != '\0') {
parseError(stderr, "余分な表現があります.");
}
return value;
}

int mygets(char *s, int n) {
fgets(s, n, stdin);
int lg = strlen(s);
if (lg > 0 && s[lg-1] == '\n') s[--lg] = '\0';
return lg;
}

int main(void) {
int value;
while (1) {
ParseError = 0;
fprintf(stderr, "\n算術式:=");
if (mygets(Buffer, BUFFERSIZE) <= 0) break;
removeWhite();
Index = 0;
value = getExpression();
if (ParseError) {
fprintf(stderr, "正しくない算術式です.\n");
} else {
fprintf(stderr, "正しい算術式です. 値は%dです.\n", value);
}
}
return 0;
}


Σ ={0, 1, (, ), ⋀, ⋁,¬}とする.
以下の生成規則をもつ拡張文脈自由文法により
開始記号 E から導出される Σ 上の記号列を論理式とよぶ.
論理式の定義
B → 0 | 1
F → {¬} B | {¬}(E)
T → F { ⋀ F }
E → T { ⋁ T
この定義において、論理式の値の評価を行うプログラムを作りたいのですが上のプログラムをどう改良すればいいでしょうか?
記号「⋀」「⋁」「¬」は,それぞれ,「&」「+」「!」で代用したいです。
もしよければ返信お願いします。

A 回答 (3件)

「改良」しても意味ないねぇ. 「変更」ならともかく.



さておき, ぶっちゃけていえば「『しかるべく』変更する」だけだよ... もちろん「上のプログラム」でなにをしているか理解できていて, かつその「論理式の定義」がなにをいっているのかちゃんとわかっていれば, だけど.
    • good
    • 0

文を丸ごと読んでおいて、これをスキャンして、


[1] (0) → 0
[2] (1) → 1
[3] ¬0 → 1
[4] ¬1 → 0
[5] 0∧0 → 0
[6] 0∧1 → 0
[7] 1∧0 → 0
[8] 1∧1 → 1
[9] 0∨0 → 0
[10] 0∨1 → 1
[11] 1∨0 → 1
[12] 1∨1 → 1
という書き換えを一度に一つだけ、[1]〜[12]の順番で適用する。(つまり[1]が適用できない場合にのみ[2]をチェックするという風にして、以下同様。)この書き換えを繰り返すと、書き換えるたびに文の長さは減少し、(文が文法に従っていれば)長さ1の文、つまり0か1になって終わる。
 要するに「→の左と一致する部分文字列を見つけて、その部分を→の右の文字列に差し替える」というだけだから、書き換え規則を(if文なんか使わずに)表(配列)にしておけば、ごく短く簡明に書ける。

 しかし、形式文法理論を学ぶ一環としての演習問題なら:この文脈自由文法に従う文を左から順に1文字ずつ処理して受理するpush down automatonを構成する(値の評価はツイデにできちゃう)ために、まずは文法を、例えばGreibach標準形(どの規則も
  P → xQ (x∈Σ)
という格好になってる形)で表しておく。…というのが真っ当なアプローチかなあ。
    • good
    • 0
この回答へのお礼

回答ありがとうございます。
ちなみに具体的にそのやり方で解いてあるソースコードがのったサイトなどはあるでしょうか?もしあれば教えていただきたいのですが...

お礼日時:2021/12/09 18:13

> ちなみに具体的にそのやり方で解いてあるソースコードがのったサイトなどは



cが使える人なら探すより書いた方が早いでしょうよ。
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!