>>933 漫画板の某スレ。
全くのスレ違いでないことを示すために、トリビアを紹介しとく。
グラフカラーリングによるレジスター割付アルゴリズムを考案した
Gregory J. Chaitinは、リーマン予想についての記事を書いている。
↓こちらが確認のweb pageです。
Thoughts on the Riemann Hypothesis
http://www.umcs.maine.edu/~chaitin/riemann.html なお、来年3月にACMから
"20 Years of the ACM SIGPLAN Conference on Programming Language Design
and Implementation (1979-1999): A Selection"
なるものが出るそうで、Chaitinもそこに懐古記事を載せるとのこと。
935 :
デフォルトの名無しさん :03/10/15 00:08
>>935 もともと左から右に見えるが、気のせいか?
まあどちらでもいいが、結合を逆にするには、例えばcalc.htmのterm()の場合、
factor(val2)ではなくterm(val2)を呼んでやればいい。
937 :
デフォルトの名無しさん :03/10/15 01:34
>>935 ループになっているのを再帰呼びだしに変えればいい。
細かいところは省略するが
void term(int *valp) {
int val, val2;
factor(&val);
if (sym == '*' || sym == '/') {
op = sym;
getsym();
term(&val2);
switch (op) {
case '*': val *= val2; break;
case '/': val /= val2; break;
}
}
*valp = val;
}
こんな感じでは(チェックはしてないよ)。
実は元の版も、再帰で書いたものをtail-recursion最適化をほどこしてループ
に展開しているわけ。
>>937 失礼、元の版は再帰だけでは書けないね。
LLパーシングだから、left-recursionはright-recursionに直さなくては
いけない。
最近パーサから離れていたのですっかり忘れてた。
939 :
名無し@沢村 :03/10/15 03:13
>>940 これもどう見ても左結合なのだが。
で、結合規則だが、BNFで表記すると、
左結合は
term ::= primary
| term OP primary
左再帰があるので、除去すると
term ::= primary { OP primary }
右結合は
term ::= primary
| primary OP term
となるので、これをそのままプログラムすればいい。
ということで、
> 右辺を下請けに任せるとそのまま左から右、再起呼び出しで行えば現在の項は保留されて、
> 先に右側を解決しにかかるので最終的に右から左になるという事でいいんでしょうか?
は合ってると言えば合っている。理解できているかどうかは知らんが。
spirit使えねー。 同じ場所に対して何度もアクションが呼び出されたりする。
>>941 BNF表記で表せればプログラムにするのは難しくないみたいですね。
自分は文法規則をBNFを使って組み立てる所の理解が不足してるみたいです。
ちゃんとした書籍でも買って勉強してみます。
結合についてはなんとなくですが理解できました。
ご丁寧にどもありがとう!
944 :
デフォルトの名無しさん :03/10/15 23:27
ちょっとコンパイラとは程遠いのですが、 数式を評価するプログラムを作っています。 (a + 2)*3 + (b + 4)*5 + 6 ⇒ a*3 + b*5 + 32 のように複雑な式を演算が少なくなるよう最適化(?)する方法ってありますか?
>>944 "symbolic algebra" simplify algorithm あたりでぐぐっても、
あまりいいのは出てこないね。
946 :
デフォルトの名無しさん :03/10/16 02:47
>>944 その例だけなら、パターンマッチで
(any + const_1) * const_2
-> any*const_1 + const_1*const_2
というような変形を行い、定数項を集めればできる。
実際、多くのコンパイラでは配列参照 a[i+1] に対するコード
*(a + (i+1) *4) を *(a+4 + i*4) のように変形している。
しかしどんな式に対しても最小の演算回数を保証するアルゴリズムとなると難
しい。結局、いろいろな変形ルールを用意しておくしかないのでは?
たとえば、x^10は素直にやると9回の掛け算が必要だが
x2 = x*x
x4 = x2*x2
x8 = x4*x4
answer = x2*x8
とすれば4回ですむ。この掛け算回数を最小にする手順を生成するアルゴリズムを
考えるだけでもけっこう大変である。
947 :
デフォルトの名無しさん :03/10/16 03:13
>>944 ドラゴンブック下巻の最適化を一通り読むことをお勧めする。
ためになるよ。
>>944 自分はツリーにして定数を出来るだけ刈っていくだけならしてるけど、
定数項を出来るだけ集めるようにするとなると、
964さんの方法で分配法則で展開するしか無いですね。
(a+3)*b -> そのまま
(a+3)*4 -> 4a + 12 に展開
>>948 すまそ、
(a+3)*4 と 4*a+12 だと全然最適化されてないっすね。
でも
(a + 2)*3 + (b + 4)*5 + 6 だと 乗算2回、加算3回、変数2個、即値5個
a*3 + b*5 + 32 だと 乗算2回、加算2回、変数2個、即値3個
なので、そこまで最適化をすることに
意味がないような気がしますが、どうでしょう?
>>946 x86の話で恐縮ですが、
定数のかけ算のばあい、昔は符号付きシフトを交えたり、
LEAをつかったりしたのと似てますね。
>>942 > 同じ場所に対して何度もアクションが呼び出されたりする。
そんなことないけど…?
switch文の嵐にしても良いよね?
952 :
デフォルトの名無しさん :03/10/17 00:10
>>945-949 遅くなりましたがレスくれた方々どうもありがとうございます。
このスレを一通り目を通しましたがあまり触れられていないので聞いてみました。
定番と呼べるアルゴリズムは無いようですね。
逆に言ったらここがコンパイラの売りとも言うことなんでしょうか。
パターンマッチの段階で展開してしまうというのは思いつきませんでした。
たとえ展開できても最適化できるとも限らないところも難問ですねぇ。
思っていいた以上に奥が深かそう・・・
>>949 加算が一つ減るなら十分やる価値あります。
> x86の話で恐縮ですが、定数のかけ算のばあい、昔は符号付きシフトを交えたり、
定数の乗算をシフトと加算に展開するのはRISCプロセッサでもやってますね。
だいたい、初期のSPARCやHPのRISCには乗算命令なかったし。後になって追加
されたけど、それでも10倍程度ならたぶんシフトと加算の方が速いんじゃないかな?
>>952 最適化の地獄の世界へようこそ(笑
あなたはいずれ、NP完全問題とは何かを肌で感じることになるでしょう。
954 :
デフォルトの名無しさん :03/10/22 20:28
LL(1)の文法で書かれたソースを解析するプログラムを作っているのですが、 右結合の演算子をどのようにすればいいかわかりません。 つまり a^b^c が a^(b^c) と解析されるようなプログラムです。 現在、 <項1>:= <項2> {( '+' | '-' )<項2>} <項2>:= <因子> {( '*' | '/' )<因子>} <因子>:=<数値>| '(' <項1> ')' のような感じで定義を行っています。 これに、'*','/'よりも順位の高い右結合の演算子はどのように定義すればいいでしょうか。 よろしくお願いします。
<項2>:= <項3> {( '*' | '/' )<項3>} <項3>:= <因子> { '^' <因子>} こうやっちゃっといて、構文木を作るときに右結合に してしまうこともできたと思ったけど。
>>955-956 ありがとうございました。
最初941見てよくわからなかったので質問したのですが、941をよく読んだらわかりました。
一応結果を書いておきます。
static void term1() {
String s;
term2();
while (token.equals("+") || token.equals("-")) {
s = token;
token = nextToken();
term2();
System.out.print(s);
}
}
static void term2() {
String s;
term3();
while (token.equals("*") || token.equals("/")) {
s = token;
token = nextToken();
term3();
System.out.print(s);
}
}
static void term3() { factor(); if (token.equals("^")) { token = nextToken(); term3(); System.out.print("^"); } } static void factor() { if (token.equals("(")) { token = nextToken(); term1(); if (token.equals(")")) { token = nextToken(); } else { System.out.println("\nERROR"); } } else { System.out.print("[" + token + "]"); token = nextToken(); } } です。 皆さんありがとうございました。(まちがってないよねぇ?)
>>926 特定のマシンのアセンブラじゃなくて
JVM(Java仮想マシン)向けに作って移植の手間軽減>ウマー
(.NETでもいいけど。)
JVM向けアセンブラならjasminがあるけど、
>>961 要するに控えめなマルチポストということですか?
>>962 同一データにリンクしているのでクロスポストと呼んで欲しいな(笑
それはともかく、大分なれてきたので簡単なスクリプトエンジンを作ってみたのですが、boost::spiritってなかなか興味深いね。 テンプレートジェネリックプログラミング+テンプレートメタプログラミングの組み合わせという超絶変態ぶりですが、 それを使うとここまで書けるのか・・・・ これでワーニングをなんとかしてエラーメッセージをジェネレートできれば yacc lex いらんぞ。 次辺り C# にもテンプレが付くそうですが、リフレクションと組み合わせたらどこまでやれるのか興味深いです。
C++のパーザ(コンパイラじゃなくてよいので)を作った人がいたら教えて欲しいんだけど、 Cのパーザを作るのと比べてどのくらい大変なものでしょうか? 当人比?倍っていう感じで。 今、Cのパーザを作っててこれはなんとかできそうなんだけど、 C++って言われたらどうしようかと思って。
さて、そろそろ次スレ立てる?
21st Century Compilers
Alfred V. Aho, Columbia University
Ravi Sethi, AT&T Bell Laboratories
Jeffrey D. Ullman, Stanford University
Monica Lam, California State University at Sacramento
ISBN: 0-321-13143-6
Publisher: Addison-Wesley
Copyright: 2004
Format: Cloth; 700 pp
Status: Not Yet Published; Estimated Availability: 02/13/2004
http://www.aw-bc.com/catalog/academic/product/0,4096,0321131436,00.html
>>972 をを。
さっそく注文しました。amazon.co.jpでは11/30発売予定となってますね。
Monica Lamはよく論文で名前みかけるけど、ついにドラゴンの仲間入りですか。
この方、中国系みたいですね。
まぁ、Monicaなら女性だろう。
>>972 キタ━━━( ´∀`)・ω・) ゚Д゚)・∀・) ̄ー ̄)´_ゝ`)-_-)=゚ω゚)ノ━━━!!!!
早速予約しますた。
977 :
デフォルトの名無しさん :03/11/12 01:30
ペーパーバック版とハードカバー版があるみたいだが。PB : ISBN 0321210913 (2003/11/30)HC : ISBN 0321131436 (2003/10/10)単なる装丁の違いなんだろうか?
しまった、ペーパーバックを注文してしまった。キャンセルせねば。
ありがとう、おかげで気付きました
>>977 10/10ってことはHCはもう出てるのか。丸善には積んであるのかな?
あぶねぇ。漏れもペーパーバック買うところだった。 つーか、もう出てたのか。全然知らなかったよ。
>>978 オレも買おうと思ってみたら二つあってハテ?って感じだったんだよね。
それよりも977改行コードミスっててスマソ
HCとPBは、まぁ同じと見て良いよね?HCにしとくか。
981 :
デフォルトの名無しさん :
03/11/23 09:18 そろそろ新スレを。