screenfuls
文件大小: unknow
源码售价: 5 个金币 积分规则     积分充值
资源说明:A ‘screenful’ is the programming analog of nanofiction: a readable program that does something interesting and fits in one screen, defined here as 80 columns by 132 lines.
Screenfuls
==========

A ‘screenful’ is the programming analog of [nanofiction][]: a readable
program that does something interesting and fits in one screen.

This repository started from the [screenfuls][] project on [Darius
Bacon’s old web page][].

[nanofiction]: http://www.wunderland.com/WTS/Andy/Nanofiction.html
[screenfuls]: http://wry.me/~darius/hacks/screenfuls/screen3.html
[Darius Bacon’s old web page]: http://wry.me/~darius/

To do
-----

Write “build scripts” so that a person can run the programs easily.

Add more screenfuls.

Add one-line summaries of each program to this file.

Candidates
----------

Norvig’s [spelling corrector].

[spelling corrector]: http://norvig.com/spell-correct.html

    import re, collections

    def words(text): return re.findall('[a-z]+', text.lower()) 

    def train(features):
        model = collections.defaultdict(lambda: 1)
        for f in features:
            model[f] += 1
        return model

    NWORDS = train(words(file('big.txt').read()))

    alphabet = 'abcdefghijklmnopqrstuvwxyz'

    def edits1(word):
       splits     = [(word[:i], word[i:]) for i in range(len(word) + 1)]
       deletes    = [a + b[1:] for a, b in splits if b]
       transposes = [a + b[1] + b[0] + b[2:] for a, b in splits if len(b)>1]
       replaces   = [a + c + b[1:] for a, b in splits for c in alphabet if b]
       inserts    = [a + c + b     for a, b in splits for c in alphabet]
       return set(deletes + transposes + replaces + inserts)

    def known_edits2(word):
        return set(e2 for e1 in edits1(word) for e2 in edits1(e1) if e2 in NWORDS)

    def known(words): return set(w for w in words if w in NWORDS)

    def correct(word):
        candidates = known([word]) or known(edits1(word)) or known_edits2(word) or [word]
        return max(candidates, key=NWORDS.get)

Kragen’s bootstrapping [PEG parser generator][].

[PEG parser generator]: https://github.com/kragen/peg-bootstrap/blob/master/peg.md



The “[BNF in Forth][]” paper by Brad Rodriguez from around 1990.

[BNF in Forth]: http://www.bradrodriguez.com/papers/bnfparse.htm

                                                                  Scr #       3
     0 \ BNF Parser                                (c) 1988 B. J. Rodriguez
     1 0 VARIABLE SUCCESS
     2 :  IN @ >R DP @ >R  >R
     3    ELSE  R> DROP  THEN ;
     4 : BNF>   SUCCESS @ IF  R>  R> R> 2DROP   >R
     5    ELSE  R>  R> DP ! R> IN !  >R THEN ;
     6 : |    SUCCESS @ IF  R> R> R> 2DROP DROP
     7    ELSE  R> R> R> 2DUP >R >R IN ! DP !  1 SUCCESS !  >R THEN ;
     8 : BNF:   [COMPILE] : SMUDGE COMPILE  SMUDGE [COMPILE] ; ; IMMEDIATE
    10
    11 : @TOKEN ( - n)   IN @ TIB @ + C@ ;
    12 : +TOKEN ( f)    IF 1 IN +! THEN ;
    13 : =TOKEN ( n)    SUCCESS @ IF @TOKEN =  DUP SUCCESS ! +TOKEN
    14    ELSE DROP THEN ;
    15 : TOKEN ( n)     ( a)  C@ =TOKEN ;

                                                                  Scr#        4
     0 \ BNF Parser - 8086 assembler version       (c) 1988 B. J. Rodriguez
     1 0 VARIABLE SUCCESS
     2 CODE     -1 # SUCCESS #) TEST, EQ IF,      \  if failing,
    10        0FDFE # W MOV, ( U ptr)                  \     backtrack to
    11        0 [RP] AX MOV, AX ' DP @ [W] MOV,        \     checkpoint
    12        2 [RP] AX MOV, AX ' IN @ [W] MOV,
    13     THEN, 4 # RP ADD, NEXT                      \  discard checkpoint
    14                                                 \     and continue
    15

                                                                  Scr#        5
     0 \ BNF Parser - 8086 assembler version       (c) 1988 B. J. Rodriguez
     1 CODE |   -1 # SUCCESS #) TEST, NE IF,        \ if passing,
     2       4 # RP ADD,                            \   discard checkpoint
     3       0 [RP] IP MOV, RP INC, RP INC,         \   and exit now
     4    ELSE, 0FDFE # W MOV,                      \ else, backtrack,
     5       0 [RP] AX MOV,    AX ' DP @ [W] MOV,   \   leaving checkpoint
     6       2 [RP] AX MOV,    AX ' IN @ [W] MOV,   \   stacked, and
     7       SUCCESS #) INC,                        \   set true for next
     8    THEN, NEXT                                \   alternate
     9
    10
    11
    12
    13
    14
    15

                                                                  Scr #       6
     0 \ BNF Parser Example #1 - pattern recog.             18 9 88 bjr 19:41
     1 \ from Aho & Ullman, Principles of Compiler Design, p.137
     2 \ this grammar recognizes strings having balanced parentheses
     3
     4 HEX    28 TOKEN '('      29 TOKEN ')'      0 TOKEN 
     5
     6 BNF:      @TOKEN DUP 2A 7F WITHIN SWAP 1 27 WITHIN OR
     7    DUP SUCCESS ! +TOKEN ;BNF
     8
     9 BNF:        '('  ')'    |       |   ;BNF
    10
    11 : PARSE     1 SUCCESS !     
    12   CR SUCCESS @ IF ." Successful " ELSE ." Failed " THEN ;
    13
    14
    15

                                                                  Scr#        7
     0 \  BNF Parser Example    #2  - infix notation        18 9 88 bjr 14:54
     1 HEX    2B TOKEN   '+'    2D  TOKEN '-'     2A  TOKEN  '*'     2F TOKEN '/'
     2        28 TOKEN   '('    29  TOKEN ')'     5E  TOKEN  '^'
     3        30 TOKEN   '0'    31  TOKEN '1'     32  TOKEN  '2'     33 TOKEN '3'
     4        34 TOKEN   '4'    35  TOKEN '5'     36  TOKEN  '6'     37 TOKEN '7'
     5        38 TOKEN   '8'    39  TOKEN '9'       0 TOKEN  
     6
     7 BNF:       '0'  | '1' | '2' |  '3' | '4' | '5' | '6' | '7'
     8     |  '8' | '9' ;BNF
     9 BNF:          |      ;BNF
    10
    11
    12
    13
    14
    15

                                                                  Scr#        8
     0 \ BNF Parser Example     #2 - infix notation         18 9 88 bjr 15:30
     1 \ from Aho & Ullman,     Principles of Compiler Design, pp.135,178
     2 : [HERE]     HERE 0 ,   -2 CSP +!  ;    IMMEDIATE
     3
     4 BNF:        '(' [HERE]  ')'  |     ;BNF
     5 BNF:        '-'     |    ;BNF
     6 BNF:        '^'  |  ;BNF
     7 BNF:        '*'   | '/'   ;BNF
     8 BNF:         ;BNF
     9 BNF:        '+'   | '-'      ;BNF
    10 BNF:          ;BNF
    11 '  CFA SWAP !      \ fix the recursion in 
    12
    13 : PARSE     1 SUCCESS !      
    14    CR SUCCESS @ IF  ." Successful " ELSE ." Failed " THEN ;
    15

                                                                  Scr #       9
     0  \ BNF  Example #3      code generation               18 9 88 bjr 21:57
     1 HEX    2B TOKEN   '+'    2D  TOKEN '-'     2A  TOKEN  '*'     2F TOKEN'/'
     2        28 TOKEN   '('    29  TOKEN ')'     5E  TOKEN  '^'
     3        30 TOKEN   '0'    31  TOKEN '1'     32  TOKEN  '2'     33 TOKEN '3'
     4        34 TOKEN   '4'    35  TOKEN '5'     36  TOKEN  '6'     37 TOKEN '7'
     5        38 TOKEN   '8'    39  TOKEN '9'       0 TOKEN  
     6
     7 BNF: {DIGIT}      '0'  | '1' | '2' |  '3' | '4' | '5' | '6' | '7'
     8     |  '8' | '9' ;BNF
     9 BNF:        @TOKEN {DIGIT} C, ;BNF
    10
    11 BNF:            |     ;BNF
    12
    13 : (,")    R COUNT DUP 1+ R> + >R       HERE SWAP DUP ALLOT CMOVE ;
    14 : ,"    COMPILE (,") 22 WORD HERE       C@ 1+ ALLOT  ;    IMMEDIATE
    15

                                                                  Scr#       10
     0 \  BNF Example #3       code generation               18 9 88 bjr 21:57
     1 :  [HERE]     HERE 0  ,   -2 CSP +!  ;    IMMEDIATE
     2
     3 BNF:      '('   [HERE]  ')'
     4                 |    BL C, ;BNF
     5 BNF:       '-'    ," MINUS "
     6                 |     ;BNF
     7 BNF:        '^'       ," POWER "
     8                 |   ;BNF
     9 BNF:       '*'      ," * "    
    10             |  '/'      ," / "    
    11             |  ;BNF
    12 BNF:              ;BNF
    13 BNF:       '+'     ." + "   
    14             |  '-'     ." - "   
    15             |  ;BNF

                                                                  Scr#       11
     0  \ BNF Example #3 - code generation                   18 9 88 bjr 21:57
     1  BNF:          ;BNF
     2  '  CFA SWAP             \ fix the recursion in 
     3
     4  : PARSE    HERE 1 SUCCESS !          
     5     CR SUCCESS @ IF HERE OVER - DUP MINUS ALLOT TYPE
     6     ELSE ." Failed" THEN ;
     7
     8
     9
    10
    11
    12
    13
    14
    15

Kragen’s [Wireworld simulator] in Ruby with ruby-processing:

[Wireworld simulator]: http://canonical.org/~kragen/sw/inexorable-misc/wireworld.rb

    # -*- coding: utf-8 -*-
    # An interactive visualization of the Wireworld cellular 
    # automaton. No persistence yet.

    class Wireworld < Processing::App
      def setup
        color_mode RGB, 1.0
        no_stroke
        smooth
        background 0.45

        @cellsize = 10              # pixels
        @nx = width / @cellsize
        @ny = height / @cellsize

        @cells = fresh_cells
        @dirty = []                 # coordinates of dirty cells

        mark_all_cells_dirty
      end

      def draw
        @dirty.each { |item| draw_cell item.first, item.last }
        @dirty = []
        run_wireworld_rule
      end

      def mouse_clicked
        x = mouse_x / @cellsize
        y = mouse_y / @cellsize

        if @cells[x][y] == :empty
          set x, y, :wire
        elsif mouse_button == LEFT
          set x, y, :empty
        else
          set x, y, :electron_head
        end
      end

      def draw_cell(x, y)
        set_color_from @cells[x][y]
        rect(x * @cellsize, y * @cellsize, 
             @cellsize - 2, @cellsize - 2)
      end

      def set_color_from(state)
        case state
        when :empty
          fill 0.5, 0.5, 0.5, 1
        when :wire
          fill 0.75, 0.75, 0.5, 1
        when :electron_head
          fill 1, 1, 1, 1
        when :electron_tail
          fill 0.75, 0.75, 0.75, 1
        end
      end

      def run_wireworld_rule
        old_cells = @cells
        @cells = fresh_cells

        each_coord do |x,y|
          # This could be optimized somewhat by only recalculating
          # the neighbors of dirty cells.
          case old_cells[x][y]
          when :electron_head
            set x, y, :electron_tail
          when :electron_tail
            set x, y, :wire
          when :empty
            # do nothing; fresh_cells are all :empty
          when :wire
            case electron_head_count old_cells, x, y
            when 1, 2
              set x, y, :electron_head
            else
              # Don’t call `set` in this case so as not to mark 
              # the cell dirty for redrawing.
              @cells[x][y] = :wire
            end
          end
        end
      end

      # This could perhaps be optimized somewhat with a sum table.
      def electron_head_count(cells, base_x, base_y)
        count = 0
        ([0, base_x-1].max..[base_x+1, @nx-1].min).each do |x|
          ([0, base_y-1].max..[base_y+1, @ny-1].min).each do |y|
            count += 1 if cells[x][y] == :electron_head
          end
        end
        return count
      end

      def each_coord
        (0..@nx-1).each do |x|
          (0..@ny-1).each do |y|
            yield x, y
          end
        end
      end      

      def mark_all_cells_dirty
        each_coord do |x, y|
          @dirty << [x, y]
        end
      end

      def set(x, y, value)
        @cells[x][y] = value
        @dirty << [x, y]
      end

      def fresh_cells
        Array.new(@nx) { Array.new(@ny, :empty) }
      end
    end

    Wireworld.new(:title => "Wireworld",
                  :width => 1024, :height => 600, 
                  :full_screen => true)

    # Local Variables:
    # compile-command: "./rp5 run wireworld.rb"
    # End:

Some kind of micro-CMCS?  Like a tiny Wiki?

Bernd Paysan’s [one-screeners][], in particular the [object system][].

[one-screeners]: http://www.jwdt.com/~paysan/screenful.html
[object system]: http://www.jwdt.com/~paysan/mini-oof.html

    \ Mini-OOF                                                 12apr98py
    : method ( m v -- m' v ) Create  over , swap cell+ swap
      DOES> ( ... o -- ... ) @ over @ + @ execute ;
    : var ( m v size -- m v' ) Create  over , +
      DOES> ( o -- addr ) @ + ;
    : class ( class -- class methods vars ) dup 2@ ;
    : end-class  ( class methods vars -- )
      Create  here >r , dup , 2 cells ?DO ['] noop , 1 cells +LOOP
      cell+ dup cell+ r> rot @ 2 cells /string move ;
    : defines ( xt class -- ) ' >body @ + ! ;
    : new ( class -- o )  here over @ allot swap over ! ;
    : :: ( class "name" -- ) ' >body @ + @ compile, ;
    Create object  1 cells , 2 cells ,

The Lisp 1.5 metacircular interpreter?

Some interpreters from EOPL?

Some things from IOCCC, if deobfuscated?

Neel Krishnaswami's [90-line compiler][] for the λ-calculus in OCaml:

[90-line compiler]: http://www.reddit.com/r/programming/comments/711ha/llvmbased_miniml_compiler_in_100_lines_of_ocaml/c05eyms

> Sure thing! Here's a compiler for the pure lambda calculus using a cbv evaluation strategy. It compiles to a triple-style pseudo-assembly, which you can easily change to your favorite actual assembly language. The registers I use are:
> 
> * sp -- the stack pointer; points to the topmost occupied element of the stack. The stack grows upwards, so incrementing it yields a new slot.
> * hp -- the heap pointer; points to the next free pointer. Allocation consists of bumping the heap pointer. You aren't getting deallocation in 100 LOC. :-)
> * ep -- the environment register. Hold a pointer to the current environment for lexical variables.
> * ret -- the return pointer. Where the current function should return to.
> * work -- a scratch register
> * newenv -- where we store the environment of a function we're about to call
> * calltgt -- where we store the address of a function we're about to jump to
> 
> The compiler is insanely junky, but hey, it's ninety lines of code. There are exactly two interesting things it does. First, it does closure conversion, and uses `expr` to represent regular asts and `cexpr` for closure converted expressions. Second, it uses a perhaps excessively-slick bit of higher order functional programming to do relocation and backpatching in a purely functional way. Basically, a relocatable piece of code is a function that takes in its start address, and returns a pair consisting of the length of the generated code, and another function which actually produces the code once you give it a table of offsets for the closure addresses.
> Some of the junky things I do is put too much code into the call sequence, rather than into the closure body. Another junky thing is that stack manipulation is incredibly lazy and naive; you could clean it up, shrink the generated code, and probably get rid of a couple of registers. Also, variable references are linear time, since I scan a linked list to find them.
> 
>     type 'a exp =
>       | Var of string
>       | App of 'a exp * 'a exp
>       | Lam of string * 'a 
> 
>     type expr = E of expr exp
>     type cexpr = C of int 
> 
>     let rec lambda_lift e env table =
>       match e with
>       | Var v -> Var v, table
>       | App(e1, e2) ->
>           let e1', table = lambda_lift e1 env table in
>           let e2', table = lambda_lift e2 env table in
>           App(e1', e2'), table
>       | Lam(x, E ebody) ->
>           let ebody', table = lambda_lift ebody (x :: env) table in
>           Lam(x, C(List.length table)), (table @ [x :: env, ebody'])
> 
>     let rec index x = function
>       | [] -> raise Not_found
>       | y :: ys -> if x = y then 0 else 1 + (index x ys)
> 
>     let rec natfold n f init = if n = 0 then init else f (natfold (n-1) f init)
> 
>     (* compile : (string list * cexpr) -> int -> int * (int list -> string list) *)
> 
>     let rec compile' (env, e) start =  
>       match e with
>       | Var x ->
>           let n = index x env in
>           (n + 3,
>            (fun _ -> 
>               ["work := ep\n"] @
>               (natfold n (fun acc -> "work := [work] + 1\n" :: acc) []) @
>               ["sp := sp + 1\n";
>                "[sp] := [work]\n"]))
>       | Lam(x, C id) ->
>           (5,
>            fun locs ->
>              ["sp := sp + 1\n";
>               "[sp] := hp\n";
>               "hp := hp + 2\n";
>               Printf.sprintf "[sp] := %d\n" (List.nth locs id);
>               "[[sp] + 1] := ep\n"])
>       | App(e1, e2) ->
>           let len1, f1 = compile' (env, e1) start in
>           let len2, f2 = compile' (env, e2) (start + len1) in
>           (len1 + len2 + 21,
>            fun locs -> 
>              let code1 = f1 locs in
>              let code2 = f2 locs in
>              (code1 @ code2 @
>               ["work := hp\n";
>                "hp := hp + 2\n";
>                "[work] := [sp]\n";
>                "[[work] + 1] := ep\n";
>                "sp := sp - 1\n";
>                "newenv := [[sp]]\n";
>                "calltgt := [[sp] + 1]\n";
>                "sp := sp - 1\n";
>                "[sp] := ep\n";
>                "sp := sp + 1\n";
>                "[sp] := ret\n";
>                "sp := sp + 1\n";
>                "ep := newenv\n";
>                Printf.sprintf "ret := %d\n" (start + len1 + len2 + 16);
>                "jump calltgt\n";
>                "work := [sp]\n";
>                "sp := sp - 1\n";
>                "ret := [sp]\n";
>                "sp := sp - 1\n";
>                "ep := [sp]\n";
>                "sp := sp - 1\n"]))
> 
>     let rec compile_closures table start =
>       match table with
>       | [] -> ([], [])
>       | pair :: tail ->
>           let (len, code) = compile pair start in
>           let code lst = code lst @ ["jump ret\n"] in
>           let len = len + 1 in
>           let (offsets, codes) = compile_closures tail (start + len) in
>           (start :: offsets, code :: codes)
> 
>     let compile e env =
>       let ce, table = lambda_lift e env [] in
>       let (start, codegen) = compile' (env, ce) 0 in
>       let start = start + 1 in
>       let codegen = (fun offsets -> codegen offsets @ ["halt\n"]) in
>       let (offsets, closuregens) = compile_closures table start in
>       codegen offsets @ (List.concat (List.map (fun f -> f offsets) closuregens))

Some things from [the demo scene][] and size-coding compos?  Maybe
some other graphics hacks?

[the demo scene]: http://canonical.org/~kragen/demo/ "Also check out pouet.net, dude"

[RSA][]-in-four-lines-of-whatever?  Andrew Kuchling's 1995 Python
version should be deobfuscatable:

    #!/usr/local/bin/python -- -export-a-crypto-system-sig -RSA-in-4-lines-Python
    from sys import*;from string import*;a=argv;[s,p,q]=filter(lambda x:x[:1]!=
    '-',a);d='-d'in a;e,n=atol(p,16),atol(q,16);l=(len(q)+1)/2;o,inb=l-d,l-1+d
    while s:s=stdin.read(inb);s and map(stdout.write,map(lambda i,b=pow(reduce(
    lambda x,y:(x<<8L)+y,map(ord,s)),e,n):chr(b>>8*i&255),range(o-1,-1,-1)))

[RSA]: http://www.cypherspace.org/rsa/

My [binary relation query
language](http://canonical.org/~kragen/binary-relations.html)?  The
Prolog implementation of an evaluator is

    :- multifile rel/3.  % because there are relational facts to add later
    rel(compose(S, R), C, B) :- rel(S, C, A), rel(R, A, B).
    rel(converse(R), B, A) :- rel(R, A, B).
    rel(intersect(R, S), B, A) :- rel(R, B, A), rel(S, B, A).
    rel(product([]), _, []).
    rel(product([R|Rs]), B, [RB|RsB]) :- 
        rel(R, B, RB), rel(product(Rs), B, RsB).

    rel(sum, [A, B], C) :- var(A), not(var(B)), not(var(C)), A is C - B.
    rel(sum, [A, B], C) :- not(var(A)), var(B), not(var(C)), B is C - A.
    rel(sum, [A, B], C) :- not(var(A)), not(var(B)), var(C), C is A + B.
    rel(sum, [A, B], C) :- not(var(A)), not(var(B)), not(var(C)), C is A + B.
    rel(=<, A, B) :- A =< B.
    rel(N, _, N) :- number(N).
    rel(i, X, X).
    rel(first, [A, _], A).
    rel(second, [_, B], B).

and presumably you could write an expression parser for the query
language as a DCG of even fewer lines.

Earlier versions of Blosxom, with comments removed?  0+5i is 144
lines, which is just 12 lines over the threshold.

Strachey's [checkers player][] in CPL. Peter Norvig [got it running][]
and critiqued it.

[checkers player]:
http://www.scientificamerican.com/article.cfm?id=system-analysis-and-programming-christopher-strachey&page=2

[got it running]: http://norvig.com/sciam/sciam.html

本源码包内暂不包含可直接显示的源代码文件,请下载源码包。