ておくれそのいち
すでに話題になってたという意味で。
Adam Petersen - Software Articles
Adam Petersen - Software Development Pages, Articles Section
Start News Articles Book Reviews
Solving FizzBuzz using compiler error messages
Using C++ template metaprogramming, I'll try to solve FizzBuzz by having the compiler output
the solution as error messages.
(略)
#include <iostream>
#define BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS
#define BOOST_MPL_LIMIT_VECTOR_SIZE 110
#include "boost/mpl/if.hpp"
#include "boost/mpl/int.hpp"
#include "boost/mpl/vector.hpp"
#include "boost/mpl/push_back.hpp"
using namespace std;
using namespace boost::mpl;
struct Fizz{};
struct Buzz{};
struct FizzBuzz{};
template<int i>
struct RunFizzBuzz
{
typedef vector<int_<i> > Number;
typedef typename if_c<(i % 3 == 0) && (i % 5 == 0), FizzBuzz,
typename if_c<i % 3 == 0, Fizz,
typename if_c<i % 5 == 0, Buzz, Number>::type>::type >::type t1;
typedef typename push_back<typename RunFizzBuzz<i - 1>::ret, t1>::type ret;
};
template<>
struct RunFizzBuzz<0> // Terminate the recusion.
{
typedef vector<int_<0> > ret;
};
int main()
{
typedef RunFizzBuzz<100>::ret::compilation_error_here res;
}
This program is impossible to outperform with respect to run-time performance; it will actually
never run! And here's the nice touch: the program will deliberately not even compile! The
interesting part is that as error message, the compiler outputs the FizzBuzz solution. Look at
the highlighted parts below:
\Main.cpp(36) : error C2039: 'compilation_error_here' : is not a member of 'boost::mpl::vector101 <SNIP long argument list>'
with
[
T0=boost::mpl::int_<0>,
T1=boost::mpl::vector<boost::mpl::int_<1>>,
T2=boost::mpl::vector<boost::mpl::int_<2>>,
T3=Fizz,
T4=boost::mpl::vector<boost::mpl::int_<4>>,
T5=Buzz,
T6=Fizz,
T7=boost::mpl::vector<boost::mpl::int_<7>>,
T8=boost::mpl::vector<boost::mpl::int_<8>>,
T9=Fizz,
T10=Buzz,
T11=boost::mpl::vector<boost::mpl::int_<11>>,
T12=Fizz,
T13=boost::mpl::vector<boost::mpl::int_<13>>,
T14=boost::mpl::vector<boost::mpl::int_<14>>,
T15=FizzBuzz,
<SNIP of elements 16 - 95>
T96=Fizz,
T97=boost::mpl::vector<boost::mpl::int_<97>>,
T98=boost::mpl::vector<boost::mpl::int_<98>>,
T99=Fizz,
T100=Buzz
]
How it works
(略)
©2005 Adam Petersen adam@adampetersen.se
詳しい解説は元記事を。
エラーメッセージで FizzBuzz をという話でした。
回答者のあげた項目がやけに具体的なんだけどどれがどの本にあるものだろう
とか気になったりして。
猫でもわかるC言語の本で勉強された方教えてー;_; | OKWave
猫でもわかるC言語を勉強しています
Microsoft Visual C++2008 Express Edition のバージョンのコンパイラで
第5章のscanf関数のところで困っていることになっていますsos
本の通りに
/*scan01.c*/
#include <stdio.h>
int main()
{
int seisu;
printf("整数値を入力してください----125");
scanf("%d",&seisu);
printf("あなたの入力した数値は%dですね",seisu);
return 0;
}
と書いてビルドをしても警告1になります、あと
/*scan01.c*/
#include <stdio.h>
#define _CRT_SECURE_NO_DEPRECATE
int main()
{
int seisu;
printf("整数値を入力してください----125");
scanf_s("%d",&seisu);
printf("あなたの入力した数値は%dですね",seisu);
return 0;
}
と書いてもエラーや警告は0になるけどデバッグ→デバッグなしで開始でいつもどうりに画面に
(コマンド プロンプト?っぽいやつに)出力をすると本の通りに
整数値を入力してください----125
あなたの入力した数値は125ですね
とならず
整数値を入力してください----125
だけが出力されます(コマンド プロンプトに)・・・
みなさんはどうやって突破したの!?いや、されたのッ!!!それともいらってはいないんですけどコンパイラの設定が悪いんでしょうか?;_;
何をどこをヘルプしたらいいやら分かりません教えてください先輩僕は一体どうしたらいいの!!!!
これ以降いっぱいscanfのこといっぱい出るのにぃ~~OTL←やっぱ僕これになるんでしょうかね・・。
ANo.4
>猫でもわかるC言語の本で勉強された方教えてー;_;
「猫でもわかるC言語」はゴミ本です、今すぐ捨てて書いてあったことは全て忘れ別の本で勉強しなおしましょう。
本を選ぶときは、以下のような記述をしている本は絶対に避けてください。
(1)if(式)文;else文;
(2)do 文;while(式);
(3)do 文;while(式)
(4)「goto文はラベルへ飛ぶ」と書き、ラベルの定義を「ラベル名:」とする
(5)exit文、書式は「exit 式;」、使うにはstdlib.hが必要
(6)a<b<cがコンパイルエラーになる
(7)double intと宣言
(8)scanf文、printf文などの記述
(9)熟練者は「*p++=toupper(*p);」と書くと記述
(10)do 文 文 文 while(式);などと「do」と「while」の間に複数の文を書ける
(11)do{文}while(式);などと「{}」が必要
(12)(10)と(11)を同一人物が別の本で書く
(13)a<bの結果が0、1以外の値が返る
(14)文字列の最後は文末コード
(15)if(!expr)goto label;... /* 処理 */label;
(16)「~」文字がC言語では未使用
(17)「^=」演算子は右辺を反転したものを左辺に代入する
(18)for(文 式;式)文
(19)','で区切られた式は右から評価する
(20)#define文、#include文などの記述
(21)printfにはdouble専用の書式は無いと記述
(A)printf("%lf",double型の式);
(B)floatの出力には%f、doubleの出力には%lf、と書きながら浮動小数の出力は%e、%gだと書いてある。
(a)0<n<16という式を使う
(b)int func(int n){int d;d=1/n;return d;}というサンプルを作る
(c)関数形式マクロの説明で「パラメータに括弧をつける」と「全体に括弧をつける」の片方だけの記述
(1)~(21)は文法の基本を知らないバカが書く記述です。
(A)~(B)関数への引数渡しの基本を知らない人間の記述です。
(a)~(c)は単なるどじでしょう。
SCM Boot Camp in Nagoya に行ってきた・・・と見せかけた SML# の多相レコードの話 - 予定は未定Blog版
$ smlsharp
SML# version 1.0.0 (2012-04-06 17:51:49 JST) for x86-mingw
# 1 + 1;
Creating library file: \s4ug./000.lib
val it = 2 : int
#
SCM Boot Camp in Nagoya に行ってきた・・・と見せかけた SML# の多相レコードの話 - 予定は未定Blog版
現在のバージョンの SML# は C ドライブ直下に一時ファイルの置き場を作って、そこに .lib やら
.o やら .s (!) やら .so やらを出力します。
この置き場は実行毎に異なり、今回の場合は「s5cc」というフォルダが作られます (1 行目にフォルダ
名が出力されている)。
対話環境を終了 (Ctrl+c) させても消えないので、自分で消すようにしましょう。
ということがあるらしいのでソースを見てみた
まずは main() があるところから
main.c
/**
* main.c
* @copyright (c) 2007-2009, Tohoku University.
* @author UENO Katsuhiro
* @version $Id: $
*/
#include <stdio.h>
#include "smlsharp.h"
/* entry point of SML# object file. */
void SMLmain(void);
int
main(int argc, char **argv)
{
sml_init(argc, argv);
#if 0
__asm__ volatile ("movl $0xaa55aa55, %%eax\n\t"
"subl $0x4000, %%esp\n\t"
"movl %%esp, %%edi\n\t"
"movl $0x4000, %%ecx\n\t"
"cld\n\t"
"rep\n\t"
"stosb\n\t"
"addl $0x4000, %%esp\n\t"
: : : "edi", "eax", "ecx", "cc", "memory");
#endif
SMLmain();
sml_finish();
return 0;
}
なんで "stosb" なんだろうかという疑問はおいといて SMLmain を探す。
(**
* GenerateMain.sml
* @copyright (c) 2011, Tohoku University.
* @author UENO Katsuhiro
*)
structure GenerateMain : sig
val generate : AbsynInterface.interfaceName list -> string
val mainSymbol : AbsynInterface.compileUnit -> {mainSymbol: string}
end =
struct
fun makeMainSymbol ({hash,...}:AbsynInterface.interfaceName) =
"SMLmain" ^ hash
fun mainSymbol ({interface={interfaceName,...}, topdecs}
: AbsynInterface.compileUnit) =
case interfaceName of
NONE => {mainSymbol = "SMLmain"} ← ※※これ?
| SOME name => {mainSymbol = makeMainSymbol name}
fun escape s =
String.translate
(fn c => if Char.isAlphaNum c orelse c = #"_"
then str c
else if ord c < 256
then "\\" ^ StringCvt.padLeft #"0" 3 (Int.toString (ord c))
else raise Control.Bug "escape")
s
fun generate interfaceNames =
let
val _ =
foldl
(fn ({hash, sourceName, place}, map) =>
case SEnv.find (map, hash) of
NONE => SEnv.insert (map, hash, sourceName)
| SOME prevName =>
raise UserError.UserErrorsWithoutLoc
[(UserError.Error,
GenerateMainError.HashConflict
(prevName, sourceName, hash))])
SEnv.empty
interfaceNames
val decs =
map (fn name =>
let
val mainSymbol = escape (makeMainSymbol name)
in
"val _ = (_import \"" ^ mainSymbol ^ "\" : () -> ()) ()\n"
end)
interfaceNames
in
String.concat decs
end
end
さらに潜っていくと
RunLoop.sml
(**
* interactive program execution
*
* @copyright (c) 2011, Tohoku University.
* @author UENO Katsuhiro
*)
structure RunLoop : sig
type options =
{asmFlags : string list,
systemBaseDir : Filename.filename,
stdPath : Filename.filename list,
loadPath : Filename.filename list,
LDFLAGS : string list,
LIBS : string list,
errorOutput : TextIO.outstream}
datatype result = SUCCESS | FAILED
val available : unit -> bool
val run : options
-> Top.toplevelContext
-> Parser.input
-> result * Top.newContext
val interactive : options -> Top.toplevelContext -> unit
end =
struct
(略)
fun run ({asmFlags, stdPath, loadPath, LDFLAGS, LIBS, errorOutput, ← この関数に降りてくる?
...}:options) context input =
let
fun puts s = TextIO.output (errorOutput, s ^ "\n")
val options = {stopAt = Top.NoStop,
dstfile = NONE,
baseName = NONE,
stdPath = stdPath,
loadPath = loadPath,
asmFlags = asmFlags}
val (_, result) =
Top.compile options context input
handle e =>
(
case e of
UserError.UserErrors errs =>
app (fn e => puts (userErrorToString e)) errs
| UserError.UserErrorsWithoutLoc errs =>
app (fn (k,e) => puts (userErrorToString (Loc.noloc,k,e))) errs
| Control.Bug s => puts ("Compiler bug:" ^ s)
| exn => puts "Compilation failed."
;
raise CompileError Top.emptyNewContext
)
val (newContext, code) =
case result of
Top.RETURN (newContext, Top.FILE code) => (newContext, code)
| Top.STOPPED => raise Control.Bug "run"
in
let
val sofile = TempFile.create "so" ←※※※
val ldflags =
case SMLSharp_Version.HostOS of
SMLSharp_Version.Unix => nil
| SMLSharp_Version.Windows =>
["-Wl,--out-implib="
^ Filename.toString (Filename.replaceSuffix "lib" sofile)]
val libfiles =
case SMLSharp_Version.HostOS of
SMLSharp_Version.Unix => nil
| SMLSharp_Version.Windows =>
map (fn x => Filename.toString (Filename.replaceSuffix "lib" x))
(!loadedFiles)
val _ = BinUtils.link
{flags = SMLSharp_Config.RUNLOOP_DLDFLAGS () :: LDFLAGS
@ ldflags,
libs = libfiles @ LIBS,
objects = [code],
dst = sofile}
で、一時ディレクトリを作る辺り
TempFile.sml
(**
* temporary file management
* @copyright (c) 2010, Tohoku University.
* @author UENO Katsuhiro
*)
structure TempFile : sig
(* takes a template of filename, and generates a fresh filename based on
* the template, and create a file of that name.
* The template must be of the form "<base>.<suffix>". ".<suffix>" may be
* omitted. If the template is empty string, a random name will be used.
*)
val create : string -> Filename.filename
val cleanup : unit -> unit
end =
struct
val mktempRetryCount = 5
val tmpDir = ref NONE : Filename.filename option ref
val tmpFiles = ref nil : Filename.filename list ref
val tmpFileCount = ref 0
fun mktemp_d retry =
if retry <= 0
then raise Fail "failed to make temporally directory"
else
let
(*
* Basis Library specification says that OS.FileSys.tmpName creates
* a new file. tmpName of SML/NJ for UNIX doesn't create a file
* because it is implemented by tmpnam(3).
*)
val tmpname = OS.FileSys.tmpName ()
val tmpname = Filename.fromString tmpname
in
(CoreUtils.rm_f tmpname;
CoreUtils.mkdir tmpname;
tmpname)
handle OS.SysErr _ => mktemp_d (retry - 1)
end
fun tmpDirName () =
case !tmpDir of
SOME dir => dir
| NONE =>
let
val dirname = mktemp_d mktempRetryCount
in
tmpDir := SOME dirname;
dirname
end
fun split template =
let
val ss = Substring.full template
val (base, suffix) = Substring.splitr (fn c => c <> #".") ss
val base = Substring.dropr (fn c => c = #".") base
in
(Substring.string base, Substring.string suffix)
end
fun makeFilename (dir, base, suffix, seqno) =
let
val num = StringCvt.padLeft #"0" 3 (Int.fmt StringCvt.DEC seqno)
val base = if base = "" then num else base ^ "-" ^ num
val filename = Filename.fromString base
val absname = Filename.concatPath (dir, filename)
in
if suffix = "" then absname else Filename.addSuffix (absname, suffix)
end
fun freshName template =
let
val dir = tmpDirName ()
val (base, suffix) = split template
fun loop () =
let
val filename = makeFilename (dir, base, suffix, !tmpFileCount)
in
if CoreUtils.testExist filename
then (tmpFileCount := !tmpFileCount + 1; loop ())
else filename
end
in
loop ()
end
fun create template =
let
val filename = freshName template
in
CoreUtils.newFile filename;
tmpFiles := filename :: !tmpFiles;
filename
end
fun cleanup () =
(
app CoreUtils.rm_f (rev (!tmpFiles));
Option.map CoreUtils.rmdir_f (!tmpDir);
tmpDir := NONE;
tmpFiles := nil;
tmpFileCount := 0
)
end
で
prim.c
/* standard C library functions for basis library implementation */
/* ANSI */
{"ldexp", (primfn*)ldexp},
{"sqrt", (primfn*)sqrt},
{"sin", (primfn*)sin},
{"cos", (primfn*)cos},
{"tan", (primfn*)tan},
{"asin", (primfn*)asin},
{"acos", (primfn*)acos},
{"atan", (primfn*)atan},
{"atan2", (primfn*)atan2},
{"exp", (primfn*)exp},
{"pow", (primfn*)pow},
{"log", (primfn*)log},
{"log10", (primfn*)log10},
{"sinh", (primfn*)sinh},
{"cosh", (primfn*)cosh},
{"tanh", (primfn*)tanh},
{"floor", (primfn*)floor},
{"ceil", (primfn*)ceil},
{"round", (primfn*)round},
{"modf", (primfn*)modf},
{"frexp", (primfn*)frexp},
{"strerror", (primfn*)strerror},
{"getenv", (primfn*)getenv},
{"free", (primfn*)free},
{"system", (primfn*)system},
{"tmpnam", (primfn*)tmpnam},
{"remove", (primfn*)remove},
{"rename", (primfn*)rename},
/* C99 */
tmpnam を使っているっぽい。けどこの関数 deprecate だよねえ。
などと書いていたら、24日にこの問題が修正された1.0.1がリリースされたとさ ○| ̄|_