Archive for the ‘备忘’ Category

数据结构课设,表达式计算

Posted on 六月 30th, 2010 in 备忘 | 9 Comments »

随便写了下,没仔细调试。

大约这么定义
double parse_expr(char *input, char **output);

input就是表达式的字符串,output是解析剩下的部分。如果output==input,就是解析失败。如果正确,返回运算结果。

用起来大约这样

    char *out, *exp="2+(1+3)*4";
    double r = parse_expr(exp, &out);
    if (out==exp){
        printf("parse fail\n");
        return 0;
    }
    printf("%s => %f \n", exp, r);

回头想下,思路跟以前写的parser几乎是葫芦画瓢,也该算是递归下降吧。

代码如下

exp.h

double parse_expr(char *input, char **output);
double parse_term(char *input, char **output);
double parse_fact(char *input, char **output);
double parse_numb(char *input, char **output);

exp.c

#include "exp.h"
 
// expr ::= term {[+-] term}
double parse_expr(char *input, char **output){
    double r=0;
    char *tmp, op;
    tmp = input;
    // factor
    r = parse_term(tmp, output);
    if (output==tmp){
        return 0;
    }
    // {[+-] term}
    tmp = *output;
    while ((op=*tmp)=='+' || op=='-'){
        double r2 = parse_term(++tmp, output);
        if (tmp==*output){
            *output = input;
            return 0;
        }
        r = (op=='+')? r+r2: r-r2;
        tmp = *output;
    }
    return r;
}
 
// term ::= factor {[*/] factor}
double parse_term(char *input, char **output){
    double r=0;
    char *tmp, op;
    tmp = input;
    // factor
    r = parse_fact(tmp, output);
    if (output==tmp){
        return 0;
    }
    // {[*/] factor}
    tmp = *output;
    while ((op=*tmp)=='*' || op=='/'){
        double r2 = parse_fact(++tmp, output);
        if (tmp==*output){
            *output = input;
            return 0;
        }
        r = (op=='*')? r*r2: r/r2;
        tmp = *output;
    }
    return r;
}
 
// fact ::= (expr) | numb
double parse_fact(char *input, char **output){
    double r=0;
    char *tmp;
    // (expr)
    if (*input=='(') {
        tmp = input+1;
        r = parse_expr(tmp, output);
        if(**output==')'){
            (*output)++;
            return r;
        }
        // if fail, output == input
        else {
            *output = input;
            return 0;
        }
    }
    // numb
    r = parse_numb(input, output);
    return r;
}
 
double parse_numb(char *input, char **output){
    double  r = 0;
    char ch, *tmp=input;
    while((ch = *tmp++)>='0' && ch<='9'){
        r = r*10+ch-'0';
    }
    *output = tmp-1;
    return r;
}

main.c

int main(){
    double r;
 
    char *out, exp[1024];
    scanf("%256s", exp);
    r = parse_expr(exp, &out);
    if (out==exp){
        printf("parse fail\n");
        return 0;
    }
    printf("%s => %f \n", exp, r);
 
    return 0;
}

写一个bootsector

Posted on 五月 26th, 2010 in 备忘 | 4 Comments »

看的这个教程 http://share.solrex.org/WriteOS/

仿照《自己动手写操作系统》的格式,除却gas确实很囧的因素,大体上还是不错的。万事开头难,在开头的bootloader这里卡了好久的说…不过动手写一下也不过半小时的功夫 TvT

机器在启动的时候可能是遍历每个磁盘分区,若有发现第512字节位置是个0xAA55的魔数,就认为这是个引导的分区了。然后就把它的前512字节装入内存,从0×7c00位置开始执行。这就是最简单的引导方式了好像。

我们把汇编代码编译成一个512bytes的二进制文件,再把它放到一个软盘的映像里就好。

boot.S

[bits 16]                       ;real mode
[org 0x7c00]                  ;put code start at 0x7c00
[section .text]
 
_start:
    mov     ax, cs            ; init seg registers
    mov     ds, ax
    mov     es, ax
    call    _print_str      
 
_print_str:
    mov     ax, str            
    mov     cx, len    
    mov     bp, ax
    mov     bx, 0x000c
    mov     dl, 0
    mov     ax, 0x1301
    int     0x10                              ;int 0x10, just as manual says
 
_loop: 
    jmp     _loop                             ; forever loop
 
str: db      "screw you guys all fucked up~",10,13
len: equ     $-str
 
times 510-($-$$) db 0                   ; fill the rest with 0
dw 0xAA55                                  ; magic number

编译之

nasm -f bin boot.S

生成一个boot.bin,下一步搞个软盘镜像

dd if=boot.bin of=boot.img bs=512 count=1
dd if=/dev/zero of=boot.img skip=1 seek=1 bs=512 count=2879

ls -l 下,大约会是这样

-rwxr-xr-x 1 ssword ssword     512 2010-05-26 21:28 boot.bin
-rw-r--r-- 1 ssword ssword 1474560 2010-05-26 21:28 boot.img
-rw-r--r-- 1 ssword ssword     399 2010-05-26 21:28 boot.S

然后打开virtualbox,设置软驱映像为boot.img。启动虚拟机就可以看到一个可爱的”screw you all”什么的了 >v<

使用rake编译C程序

Posted on 五月 20th, 2010 in 备忘 | No Comments »

每次修改代码一般只会涉及一部分文件,大部分代码都是不必重复编译的。而且编译明显是分步骤也有依赖关系,比如要测试程序就得先链接出一个可执行文件,要链接就得先编译成.o。。。所以就有了make,自动分析任务的依赖关系,只对有变更的文件执行编译,省心省时间。

不过make的语法晦涩啊…就有了rake

rake提供了file函数可以指明文件的依赖关系,比如:

file 'fdict.o' => ['src/fdict.c', 'src/fdict.h'] do
  sh 'gcc -Wall -c src/fdict.c'
end
file 'test.o' => ['src/test.c'] do 
  sh 'gcc -Wall -c src/test.c'
end

file就是个ruby的函数调用,把重复的东西去掉很简单

CFlags = '-Wall'
 
[
  ['src/fdict.c', 'src/fdict.h'],
  ['src/test.c']
].each do |fn_c, *_|
  fn_o = File.basename(fn_c).ext('o')
  file fn_o => [fn_c, *_] do
    sh "gcc #{CFlags} -c #{fn_c}"
  end
end

再就是链接和执行

OFiles = %w{fdict.o test.o}
 
task :run => [:link] do 
  sh "./test"
end
 
task :link => OFiles do
  sh "gcc #{CFlags} #{OFiles.join(' ')} -o test"
end

每修改两行C程序到控制台下边一个rake run就可以立即执行,这一来写c就有点像写脚本了。

rails使用paperclip插件上传时遇到500 Internal Server Error

Posted on 五月 11th, 2010 in 备忘 | 18 Comments »

有可能是imageMagick没装利索。找不到imagemagick,显示错误信息的时候试图把上传的文件对象序列化,就505了。

sudo apt-get install imagemagick --fix-missing

使用三方库就得做好不可预料事件的准备哇

关于paperclip的使用,这两篇简介好像不错:
http://jimneath.org/2008/04/17/paperclip-attaching-files-in-rails/
http://thewebfellas.com/blog/2008/11/2/goodbye-attachment_fu-hello-paperclip

ps: 又遇到了个没预料的问题,上传validates_attachment_content_type指定的类型之外的文件时候同样会遇到个500 internal server error,未解中。

踩踩数据结构什么的 =“=

Posted on 五月 8th, 2010 in 备忘 | 5 Comments »

发觉算法太弱了 =”=

当年在ACM那里呆了两天就隐身了,可惜那个老师非常非常非常好的(实验室里还有空调 >_<)。总觉得这玩意水太深,掉进去就出不来了....“不成熟的优化乃万恶之源”这话又正好应了惰性心理,心安理得地“出了性能问题再说之前先弄出来再说管算法干嘛”...可现实往往是,不会算法你压根就弄不出来...

先从一棵二叉查找树开始好了。挖坑慢慢填,时间有的是(?)

module BTree where
 
data BTree a b = Empty 
               | BNode {
                    kv :: (a, b), 
                    left :: BTree a b,
                    right :: BTree a b
               } 
               deriving(Show, Eq)
 
insert :: (Ord a) => (a, b) -> BTree a b -> BTree a b
insert (k,v) Empty = BNode (k, v) Empty Empty
insert (k,v) pnode@(BNode (pk, _) lnode rnode) 
    | k == pk   = pnode { kv = (k,v) }
    | k <  pk   = pnode { left  = insert (k,v) lnode }
    | k >  pk   = pnode { right = insert (k,v) rnode }
 
find :: (Ord a) => a -> BTree a b -> Maybe b
find k Empty = Nothing
find k (BNode (pk,pv) lnode rnode)
    | k == pk = Just pv
    | k <= pk = find k lnode
    | k >  pk = find k rnode
find _ _ = Nothing
 
remove :: (Ord a) => a -> BTree a b -> BTree a b
remove k Empty = Empty
remove k pnode@(BNode (pk,pv) lnode rnode) 
    | k == pk = merge lnode rnode
    | k <= pk = pnode { left = remove k lnode }
    | k >  pk = pnode { right = remove k rnode }
 
merge :: (Ord a) => BTree a b -> BTree a b -> BTree a b
merge lnode rnode = fromList $ (toList lnode) ++ (toList rnode)
 
--helper
isEmpty Empty = True 
isEmpty _     = False
 
fromList :: (Ord a) => [(a,b)] -> BTree a b
fromList = foldl (flip insert) Empty 
 
toList :: BTree a b -> [(a,b)]
toList Empty = [] 
toList (BNode (k,v) lnode rnode) = 
    (toList lnode) ++ [(k,v)] ++ (toList rnode)
 
-- for test
root = fromList $ [
    (4, "fleurer"), 
    (10, "ssword"), 
    (100, "ssword"), 
    (2, "xx")]

haskell做数据结构好像别扭的很…不用ST Monad或者IO的话什么都是值还不能引用,像二叉树的旋转什么的就没想出常数时间的办法。像上面那个remove就直接简单粗暴了orz

(邪恶音:用ST Monad不就好了嘛)
(ST Monad都用了还用haskell干嘛 TvT)