我的shell会算矩阵,你的呢
1 2 3 4 | $ [1\;2\;3].*[4 5 6] | sed 's/;/\n/g' [4 5 6 8 10 12 12 15 18] |
实现:
我今天知道有个函数名叫command_not_found_handle于是写了下面代码
1 2 3 | $ command_not_found_handle(){ > /f/julia/bin/julia -e "print($1 $2 $3 $4 $5 $6 $7 $8 $9)" > } |
1 2 3 4 | $ [1\;2\;3].*[4 5 6] | sed 's/;/\n/g' [4 5 6 8 10 12 12 15 18] |
实现:
我今天知道有个函数名叫command_not_found_handle于是写了下面代码
1 2 3 | $ command_not_found_handle(){ > /f/julia/bin/julia -e "print($1 $2 $3 $4 $5 $6 $7 $8 $9)" > } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | <body> <script> let $ = parent => (tagName, attr, fn) => { if(tagName){ let node = Object.assign(document.createElement(tagName), attr); fn && fn($(node)); (parent || document.body).appendChild(node); }else{ fn(parent); } }; let $E = ev => fn => p => p.addEventListener(ev, fn); let click = $E('click'); $()("div", {style: 'color: red;'}, $ => { $("ul", {style: 'text-decoration: underline;'}, $ => { for(let i = 0; i < 10; ++i){ $("li", {innerText: i}, $ => { $(null, null, click(_ => alert(i))) }); } }); }); </script> </body> |
最近又需要嵌入CRuby,又遇到了这个问题,
主要是当使用net/http等socket相关的库时,会提示找不到read_nonblock方法。
这个问题的解决方案很简单,补充一个定义即可
1 2 3 4 5 | class IO def read_nonblock(size, buf = nil, exception) __read_nonblock(size, buf, exception) end end |
但是使用ruby或者irb时就没有这个问题,为什么呢
(这也不是操作系统相关的问题,虽然我用的是windows)
irb下通过IO.instance_method(:read_nonblock).source_location可以发现这个方法的定义在一个叫”<internal:prelude>”的文件中定义,显然是内部自己的奇怪操作。
这个定义可以通过ruby_init_options函数来初始化,然而。
然而经过搜索发现这个函数一直有人提出,将它导出作为feature,结果从1.9到2.4都没有实行,这个函数直到现在,现成编译的版本从未导出符号。
所以,现在初始化ruby解释器,如果不想从源码修改去掉函数的static存储类关键字这里开始,一个比较合适的写法是:
1 2 3 4 5 6 7 8 9 10 11 12 13 | int argc = 0; char **argv = 0; static char* args[] = {(char *)"ruby", #ifdef WIN32 (char *)"nul" #else (char *)"/dev/null" #endif }; ruby_sysinit(&argc, &argv); ruby_init(); ruby_init_loadpath(); ruby_process_options(2, &args); //假装有个ruby程序执行了一个程序,从而隐含调用prelude定义 |
最近做codewars上的Haskell的水题的时候(难题我也不会),基本上是尽量用一种point-free的风格(https://en.wikipedia.org/wiki/Tacit_programming)去写的。我个人理解也就是函数的实现不写出参数,只通过curry和组合等来实现,例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 | -- let add a b = a + b let add = (+) -- let factorial n = product [1..n] let factorial = product . enumFromTo 1 -- let isPalindrome str = reverse str == str let isPalindrome = reverse >>= (==) -- 下面几个的point-free style作为练习 -- let k f x = f -- let g x y f = f x y -- let triple f x = f x x x |
另外这里也不认可出现用lambda形式代入参数如:
1 2 | let g = \x y f -> f x y --这也不是本文讨论的 |
这里用一个生成的方法来实现一个比较通用的方案,其实应该也可以用haskell的point-free风格代码来实现这套代码而不是生成,这里用Ruby生成。
注意到:
1 | let f x y = a (b x y) |
也可以写成
1 2 3 | let f x y = ((a.) . b) x y -- 即 let f = (a.) . b |
每次多一个参数就会是最里面多一个
1 2 | ... (a .) . ... ... ( ((a .) .) . (a .)) . ... |
等等的结构,也就是组合前面是一个(a .)的形式
另外,如果我们把tuple视为栈
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | > let f = (3, (2, 1)) > let push = (,) push 4 f -- (4, (3, (2, 1))) > let pop = snd pop f -- (2, 1) > let modify = first modify (+1) f -- (4, (2, 1)) > let apply = (uncurry ($) . (first *** id)) > let g = ((+1), (2, 3)) apply g -- (3, 3) 另外实现几个从forth拿过来的栈运算 >let vdup = modify (fst >>= (,)) 复制栈顶 (a, b) -> b vdup f -- (3, (3, (2, 1)) >let vswap = modify ((fst . snd) &&& (fst &&& (snd . snd))) 交换栈顶二个元素 (a, (b, c)) -> (b, (a, c)) vswap f -- (2, (3, 1)) >let vover = modify ((fst . snd) &&& id) over运算, 把栈顶的下一个元素复制一份压在顶上,(a, (b, c)) -> (b, (a, (b, c))) vover f -- (2, (3, (2, 1))) 等等可以把forth的栈操作都实现出来 |
于是这样就可以实现一组DSL(https://github.com/Artoria/pf-builder)了,比如海伦公式的实现
heron a b c = let s = (a + b + c) / 2 in s * (s – a) * (s – b) * (s – c)
下面的思路是通过build生成函数体
首先把三个参数a b c转成[c, b, a]
然后应用 (/2) . sum得到s
然后把s变成(s-), map到[c, b, a]上,变成[s-c, s-b, s-a], 然后对他它用product, 并且乘上这个积和s
就是结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | puts Builder.new{ push_arg modify "(: [])" push_arg push_const "(:)" apply apply push_arg push_const "(:)" apply apply modify_dup "(/2) . sum" vover vover modify "(-)" push_const "map" apply apply modify "product" push_const "(*)" apply apply modify "sqrt" }.finish! |
得到的结果,反正就是不能看了:
1 | ((((((((((((((((((((((((((( fst . (first (sqrt))) . (uncurry ($) . (first *** id))) . (uncurry ($) . (first *** id))) . ((,) ((*)))) . (first (product))) . (uncurry ($) . (first *** id))) . (uncurry ($) . (first *** id))) . ((,) (map))) . (first ((-)))) . ((fst . snd) &&& id)) . ((fst . snd) &&& id)) . (first ((/2) . sum))) . (fst >>= (,))) . (uncurry ($) . (first *** id))) . (uncurry ($) . (first *** id))) . ((,) ((:)))) .) . flip (,)) . (uncurry ($) . (first *** id))) . (uncurry ($) . (first *** id))) . ((,) ((:)))) .) . flip (,)) . (first ((: [])))) .) . flip (,)) undefined) |
另外,因为point-free的函数也是函数,可以嵌套
比如fib n = foldr (\_ (x, y) -> (y, x+y)) (1, 0) [1..n]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | puts Builder.new { push_arg modify "enumFromTo 1" push_const "(1, 0)" push_const Builder.new{ push_arg vpop push_arg modify "snd &&& (liftA2 (+) fst snd)" }.finish! push_const "foldr" apply apply apply modify "snd" }.finish! |
得到的结果
1 | ((((((((((( fst . (first (snd))) . (uncurry ($) . (first *** id))) . (uncurry ($) . (first *** id))) . (uncurry ($) . (first *** id))) . ((,) (foldr))) . ((,) (((((((( fst . (first (snd &&& (liftA2 (+) fst snd)))) .) . flip (,)) . snd) .) . flip (,)) undefined)))) . ((,) ((1, 0)))) . (first (enumFromTo 1))) .) . flip (,)) undefined) |
毕竟Bellard大牛的OTCC里面就是到处飞机器码,并且,他是一边解析词法符号一边就直接产生了,真是棒棒的不按套路却又无比正经的写法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | =begin Author: 晴兰@66RPG UID=131313 LICENSE: CC-BY-SA 3.0 [url]http://creativecommons.org/licenses/by-sa/3.0/deed.zh[/url] Purpose: Simple Machine Code Generator. Limited operation supported =end CallWindowProc = Win32API.new 'user32', 'CallWindowProcW', 'pLLLL', 'L' def prolog(num_of_var = nil) [0x55, 0x8b, 0xec].pack("C*") + (num_of_var ? [0x83, 0354, num_of_var * 4].pack("C*") : "") end def epilog [0xc9, 0xc2, 0x10].pack("CCS") end def render(list, num_of_var = nil) prolog(num_of_var) + render_rec(list) + epilog end def check_var(list) return -4 * list[1] if list[0] == :var raise "lvalue required for #{list.inspect}" end def render_rec(list) case list.first when :lit [0xb8, list[1]].pack("CL") when :arg [0x8b, 0105, 4 + list[1] * 4].pack("C*") when :do list[1..-1].map{|x| render_rec(x)}.join when :var [0x8b, 0105, -4 * list[1] ].pack("C*") when :assign id = check_var(list[1]) render_rec(list[2]) + [0x89, 0105, id].pack("C*") when :+, :-, :&, :^, :| render_rec(list[2]) + "\x50" + render_rec(list[1]) + [0132, "+|ab&-^".index(list.first.to_s) << 3 | 3, 0302].pack("C*") when :<, :>, :'==', :'!=', :>=, :<= v = list.first.to_s l = v.length f = v.ord rescue v[0] u = "0000G+000000<HF>".index((f + (l > 1 ? 10 : 0)).chr) render_rec(list[2]) + "\x50" + render_rec(list[1]) + [0132, 073, 0302, 0x0f, 0x90 + u, 0300, 0x81, 0340, 0xff, 0x00, 0x00, 0x00].pack("C*") when :nil; "" when :if cond, thenpart, elsepart = list[1..-1].map{|x| render_rec(x)} thenpart += [0xe9, elsepart.length].pack("CL") cond += [0x85, 0300, 0x75, 0x05, 0xe9, thenpart.length].pack("CCCCCL") cond + thenpart + elsepart when :for init, cond, incr, body = list[1..-1].map{|x| render_rec(x)} addbyte = [0x85, 0300, 0x75, 0x05, 0xe9, body.size + incr.size + 5].pack("CCCCCL") fbody = body + incr + [0xe9, -(body.size + incr.size + cond.size + addbyte.size + 5)].pack("CL") init + cond + addbyte + fbody end end x = render( [:do, [:assign, [:var, 1], [:lit, 0]], [:for, [:assign, [:var, 2], [:lit, 1]], [:<, [:var, 2], [:lit, 101]], [:assign, [:var, 2], [:+, [:var, 2], [:lit, 1]]], [:assign, [:var, 1], [:+, [:var, 1], [:var, 2]]] ], [:var, 1] ], 2 ) =begin int var1 = 0; for(int var2 = 1; var2 < 101; var2+=1) var1 += var2; return var1 =end p CallWindowProc.call x, 0, 0, 0, 0 #=>5050 |
一种新的调用API的包装,因为API不包装也可以调用,其实就是自己的脚本综合练习一类的东西吧:
用法:
鼠标指针:
1 2 3 4 5 6 7 8 | def mouse_pos api{ import 'user32' # 点是两个uint, 传入的int[2].*是两个uint的指针 return GetCursorPos(uint[2].*).out[0].values #传出参数的第0个是这个指针,values取得他的内容(两个点) } end |
自定义结构体的鼠标指针:
1 2 3 4 5 6 7 8 9 10 | def point(x = int(0), y = int(0)) tuple(x, y) end def mouse_pos api{ import 'user32' return GetCursorPos(*point).out[0].values } end |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 | Win32API rescue require 'win32api' #API 1.7 # http://seiran.mist.so class API class CPtr RMM = Win32API.new("Kernel32", "RtlMoveMemory", "LLL", "L") SLEN = Win32API.new("Kernel32", "lstrlenA", "L", "L") WLEN = Win32API.new("Kernel32", "lstrlenW", "L", "L") def initialize(start, len = 0) @start, @len = start, len end def [](st, le) buf = ""*le RMM.call *[buf, @start+st, le].pack("pLL").unpack("L*") buf end def +(a) CPtr.new(@start+a, @len) end def []=(st, le, str) RMM.call *[@start+st, str, [le,str.size].min].pack("LpL").unpack("L*") end def to_s(size = nil) a = SLEN.call(to_i) size ||= a self[0, [size, a].min] end def to_ws(size = nil) a = WLEN.call(to_i) size ||= a self[0, [size, a].min * 2] end def to_i @start end end module ArrayType def [](size) API::Tuple.new([self] * size) end end module PointerType def *(*a) API::Pointer.new(self) end def to_ary(*a) [API::Pointer.new(self)] end end class Tuple include ArrayType include PointerType def initialize(args) @args = args end def pack @objects = [] @mark = [] @valuestr = "" pos = 0 @args.each{|x| case x when Integer then @valuestr << [x].pack("L"); pos += 4 when String then @valuestr << [x].pack("p"); @mark << x; pos += 4 else @objects << [x, pos]; @valuestr << (u = x.pack); pos += u.size end } @valuestr end def unpack(ptr) out = [] @objects.each{|x| a, b = x; out << a.unpack(ptr + b); } out end end class SingleType include ArrayType include PointerType def initialize(a = 0, packchar = "L", size = 4); @a = a; @p = packchar; @size = size; @buf = [@a].pack(packchar);end def pack; @buf; end def unpack(ptr); ptr[0, @size].unpack(@p).first; end end def uint(a = 0) SingleType.new(a) end def int(a = 0) SingleType.new(a, "l") end alias ulong uint alias long int alias uint32 uint alias int32 int def char(a = 0) SingleType.new(a, "c") end def byte(a = 0) SingleType.new(a, "C") end alias uchar byte alias u8 byte alias uint8 byte alias int8 char def short(a = 0) SingleType.new(a, "s") end def ushort(a = 0) SingleType.new(a, "S") end alias uint16 ushort alias int16 short def longlong(a = 0) SingleType.new(a, "q", 8) end def ulonglong(a = 0) SingleType.new(a, "Q", 8) end alias uint64 ulonglong alias int64 longlong def float(v) SingleType.new(v, "F", 4) end def double(v) SingleType.new(v, "D", 8) end alias real float alias real32 float alias real64 double def packed_char(v) SingleType.new(v, "c", 1) end def packed_short(v) SingleType.new(v, "s", 2) end class PointerToTuple def initialize(tuple, ptr) @tuple, @ptr = tuple, ptr end def value @tuple.unpack(@ptr) end end class Pointer include ArrayType include PointerType def initialize(obj = API::Tuple.new([])); @obj = obj; @obj = API::Tuple.new([@obj]) unless Tuple === @obj;@str = @obj.pack; @ptr = [@str].pack("p"); end def pack; @ptr; end def unpack(ptr); PointerToTuple.new(@obj, API::CPtr.new(ptr[0, 4].unpack("L").first)) end end class BufferAnsiString include ArrayType include PointerType def initialize(size = nil, &b) r = if b then b.call else nil end @size = size || r.size @buf = r || ""*@size end def pack @buf end def unpack(ptr) ptr.to_s(@size) end end class BufferWideString include ArrayType include PointerType def initialize(size = nil, &b) r = if b then b.call else nil end @size = (size ? size * 2 : nil)|| r.size @buf = r || ""*@size end def pack @buf end def unpack(ptr) ptr.to_ws(@size) end end class Buffer include ArrayType include PointerType def initialize(size) @size = size @buf = ""*@size end def pack @buf end def unpack(ptr) ptr[0, @size] end end def pointer(obj = tuple()) Pointer.new(obj) end def buffer(size) Buffer.new(size) end def string(size = nil, &b) BufferAnsiString.new(size, &b) end def wstring(size = nil, &b) BufferWideString.new(size, &b) end def array(size, typesym) tuple(*Array.new(size).map{send typesym}) end attr_accessor :caller class ResultType def initialize(ret, out) @ret, @out = ret, out end def to_int @ret.to_int end def to_i @ret.to_i end def coerce(v) case v when Fixnum; [v, to_int] when String; [v, to_str] end end def method_missing(sym, *args) @ret.send sym, *args end def to_str @ret.to_str end def to_s @ret.to_s end def value @ret end def out @out end def first @out.first end def last @out.last end def [](a) @out[a] end end class Caller attr_accessor :imports def initialize self.imports = [] @api = API.new end def guess(sym, num) params = "L"*num vsyms = ["_#{sym}", "#{sym}", "_#{sym}@#{num}", "#{sym}@#{num}"] self.imports.map{|x| vsyms.map{|y| begin Win32API.new(x, y, params, "L") rescue LoadError # Ruby >= 1.9 nil rescue RuntimeError # RMXP nil end } }.flatten.compact end def call_win32api(sym, *args) t = API::Tuple.new(args) r = t.pack v = guess(sym, r.size / 4) ret = v[0].call *r.unpack("L"*args.size) out = t.unpack(API::CPtr.new([r].pack("p").unpack("L").first)) ResultType.new(ret, out) end def asm_push(a) @api.tuple(@api.packed_char(0x68), a) end def asm_addesp(a) @api.tuple(@api.packed_short(0xc483), a) end def asm_func_begin @api.tuple(@api.packed_short(0x8b55), @api.packed_char(0xec)) end def asm_func_end @api.int(0x0010c2c9) end def asm_call(a) @api.tuple( @api.packed_char(0xb8), @api.int(a), @api.packed_short(0xd0ff) ) end def call_stdcall(addr, *args) t = [asm_func_begin] t.concat args.reverse.map{|x| asm_push(x)} t.concat [asm_call(addr)] t.concat [asm_func_end] api{ import 'user32' return CallWindowProc pointer(tuple(*t)), 0, 0, 0, 0 } end def call_cdecl(addr, *args) t = [asm_func_begin] t.concat args.reverse.map{|x| asm_push(x)} t.concat [asm_call(addr)] t.concat [asm_addesp(@api.char(args.size * 4))] t.concat [asm_func_end] api{ import 'user32' return CallWindowProc pointer(tuple(*t)), 0, 0, 0, 0 } end end def setup self.caller = Caller.new end def import(name) self.caller.imports << name unless self.caller.imports.include?(name) self end def tuple(*args) Tuple.new(args) end def method_missing(sym, *args) self.caller.call_win32api(sym, *args) end def stdcall(addr, *args) self.caller.call_stdcall(addr, *args) end def ccall(addr, *args) self.caller.call_cdecl(addr, *args) end end def api(&b) x = API.new x.setup x.instance_eval(&b) if b x end |
1. BMVC是什么?
BMVC是RGSS中实现多个窗口或者精灵,或者他们的混合架构的一个脚本,可以用来简化代码。
相对于单个的窗体Window/精灵Sprite而言,BMVC可以同时有多个显示对象被控制。比如应用物品时,物品描述窗口,物品选择窗口和对象选择窗口是三个窗口,但有关联。可以用BMVC实现。
而相对于场景Scene而言,BMVC比Scene要轻量,也可以嵌入Scene中。
所以也可以放在事件中,比如一个物品选择窗口,没必要创建一个类。
BMVC是RGSS系列上对MVC模式(http://zh.wikipedia.org/wiki/MVC)的一个特化实现,因为RGSS默认脚本本身已经实现一系列与模型有关的东西比如$game_…,这里只需要和他们建立各种关系即可,这种关系模型在本脚本叫做BindingModel,故本脚本命名为BindingModel-View-Controller
2. 如何使用?
有两个重要的方法,一个是K,一个是B,K创建视图和有关的控制器,B创建和模型的绑定。
写在K里面的self.xxx,如果他是一个window或者sprite的话,会自动update和dispose
第一个例子,显示一个有Hello world的窗口,按回车(Input::C)时退出,因为不含任何可变的数据,所以没有用到B。
1 2 3 4 5 6 7 | K{ a = self.window = Window.new a.width = 132 a.height = 132 self.bitmap = a.contents = Bitmap.new(100, 100) self.bitmap.draw_text(a.contents.rect, "Hello world") }.run :C => :exit |
下面这个例子的窗口将要显示一个全局变量$a,并且当你按下回车键时,$a会加上1,并且显示也对应变化,注意变化的部分用B{}括起来。相对于上面那个例子,实际上就是把不变的”Hello world”换成了变化的$a.to_s,这里我们用B{$a.to_s}括起来。(同时加上了contents.clear清除内容这样的行为,不然前后写的文字会重叠在一起)
1 2 3 4 5 6 7 8 9 10 11 | $a = 0 K{ a = self.mywindow = Window.new self.mywindow.width = 132 self.mywindow.height = 132 self.bitmap = self.mywindow.contents = Bitmap.new(100, 100) B{ self.bitmap.clear self.bitmap.draw_text(0, 0, 100, 100, B{$a.to_s}) } }.run :B => :exit, :C => proc{$a += 1} |
因为按下回车键时,$a加上了1,所以$a.to_s会变化,B{$a.to_s}会把这个变化反馈给外面那个B{},
因此重新进行了绘制.
实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 | module Kittiko end module Kittiko::BindingModel attr_accessor :block def self.stack @stack ||= [] end def changed? @changed end def check_block @check_block ||= [] end def add_block(&b) check_block << Kittiko::Binding.new(&b) end def B(&b) if Kittiko::BindingModel.stack[-1] && !Kittiko::BindingModel.stack[-1].sealed Kittiko::BindingModel.stack[-1].add_block &b b.call else b.call end end def calc @cache = block.call end def update_binding if check_block.empty? @cache ||= calc else if @model_cache != (a = check_block.map{|x| x.calc}) @model_cache = a @cache ||= calc else @cache end end end end class Kittiko::Binding include Kittiko::BindingModel attr_accessor :sealed def initialize(&b) self.sealed = false Kittiko::BindingModel.stack.push self self.block = b b.call if b Kittiko::BindingModel.stack.pop self.sealed = true end end class Kittiko::Container include Kittiko::BindingModel attr_accessor :sealed def initialize(str, &b) @__symbols__ = [] self.sealed = false Kittiko::BindingModel.stack.push self instance_eval str instance_eval &b if b self.block = proc{} Kittiko::BindingModel.stack.pop self.sealed = true end def method_missing(sym, *args) @__symbols__.push(('@'+sym.to_s.chomp("=")).to_sym) (class << self; self; end).send :attr_accessor, sym.to_s.chomp("=") send sym, *args end def each @__symbols__.each do |x| yield instance_variable_get(x) end end def reverse_each @__symbols__.reverse.each do |x| yield instance_variable_get(x) end end def update each{|x| x.update if x.respond_to?(:update)} update_binding end def dispose reverse_each{|x| x.dispose if x.respond_to?(:dispose)} end def run_proc(v) case v when Symbol send v when Kittiko::Container v.run when Proc instance_eval &v else instance_eval v end end def run_loop(opt = {}) @exit = false until @exit run_once(opt) end end def run_once(opt = {}) Graphics.update Input.update update opt.each{|k, v| run_proc(v) if case k when Symbol Input.trigger?(Input.const_get(k)) when Proc instance_eval &k end } end def run(opt = {}) run_loop opt dispose end def exit @exit = true end def self.uniform_define_setter(*symbols) symbols.each do |sym| class_eval " def #{sym}(value) each{|x| x.#{sym} = value } end " end end uniform_define_setter :ox, :oy, :x, :y, :zoom_x, :zoom_y, :angle, :opacity, :content_opacity, :back_opacity, :z, :width, :height, :active, :mirror, :bush_depth, :blend_type, :color, :tone, :visible end def K(a = "", &b) return Kittiko::Container if a == "" && !b Kittiko::Container.new(a, &b) end class Kittiko::EventBase def self.keypress?(k) proc{Input.press?(Input.const_get(k))} end def self.keytrigger?(k) proc{Input.trigger?(Input.const_get(k))} end def self.keyrepeat?(k) proc{Input.repeat?(Input.const_get(k))} end end class Kittiko::Scope def self.[](name) BindObject.new(name) end class BindObject def initialize(name) @name = name end [:+, :-, :*, :/, :<, :>, :==, :>=, :<=].each{|x| class_eval %{ def #{x}(rhs) u = @name lambda{ instance_variable_get(u) #{x} rhs} end } } end end E = Kittiko::EventBase S = Kittiko::Scope |
其实在上古时代也没有php啦asp这些神器。。有perl或者甚至C语言来做服务器网页就已经很不错了。。。这里的本质是通过执行这些程序,输出的文本,当做HTTP内容返回。如果你看见有些老网站的地址中有/cgi-bin/,那基本上就是了。
这里兰兰用的是WAMP,windows下的一个一键快捷安装的个人服务器套件。如果你没有修改他的设置,比如装在C:\WAMP,那么这个目录应该是C:\WAMP\cgi-bin,新建一个hello.cmd,输入下面的代码:然后访问http://localhost/cgi-bin/hello.cmd?name=Hello&var=3就可以看到结果。不过这个代码的最后一行set %b:~1,-1%和中间某行call :parse_uri “%QUERY_STRING%”实际上可以被注入代码,因此用于生产环境是很不安全的,这里仅仅是用来卖萌(demostration)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | @echo off echo Content-Type:text/html; charset=GBK echo. echo ^<H1^>Hello world^</H1^> call :parse_uri "%QUERY_STRING%" if not "%name%"=="" ( @echo Your name is ^<font color=#F00^>%name%^</font^>^<BR/^> @echo Your var is ^<font color=#F00^>%var%^</font^>^<BR/^> ) echo. goto :eof :parse_uri set a=%* set b=%a:&=&set % set %b:~1,-1% |
转载本文在您同意接受CC协议(NC-ND)情况下进行,可以参考:
http://creativecommons.org/licenses/by-nc-nd/3.0/
给一个Ruby程序,把他翻译成语义上等价的其他程序。下面全部以C++为例,且不需要处理AST。 read more