`
febird
  • 浏览: 247363 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

简单的代码生成器创建领域语言

    博客分类:
  • C++
阅读更多

有一类问题,代码模板相同,但有少部分地方不同,一般可以写一个复杂的程序,使用不同的选项,完成不同的任务。或者,把公共的部分抽象成一个代码库,然后在不同程序中引用。但是,如果公共的部分很少,并且比较“专用”,或者因为其它原因,比较难以部署。怎么办?

实际上,有另一种完全不同的编程模式来实现:代码生成器。unix世界中最知名的代码生成器莫过于lex和yacc了。但是,不比每个代码生成器都那么复杂,比如这个代码生成器就非常简单,它只是简单地转换行记录:

 

#! /bin/sh

field_seperator="||"
output=b
while getopts :F:vo: arg
do
case $arg in
        F ) field_seperator=$OPTARG;;
        v ) ;;
        o ) output=$OPTARG;;
        : ) echo "$0: missing arg for -$OPTARG " >&2
            exit;;
        \?) echo "Invalid option -$OPTARG ignored." >&2
            exit;;
esac
done

if [ $OPTIND -gt $# ]
then
#       echo OPTIND=$OPTIND argc=$# >&2
        echo "no program" >&2
        exit
fi
program=${!#}

echo field_seperator=$field_seperator

cat > a.cpp <<+TemplateCFile
#include <vector>
#include <string.h>

#include <stdio.h>

const char field_seperator[]="||";

void split_row(char* line, std::vector<char*>& F, const char* fs)
{
        char* col = line;
        F.resize(0);
        size_t fslen = strlen(fs);
        if (fslen == 1) {
                for (;;) {
                        F.push_back(col);
                        col = strchr(col, fs[0]);
                        if (col) {
                                col[0] = '\0';
                                col += 1;
                        } else
                                break;
                }
        }
        else {
                for (;;) {
                        F.push_back(col);
                        col = strstr(col, fs);
                        if (col) {
                                col[0] = '\0';
                                col += fslen;
                        } else
                                break;
                }
        }
}

int main(int argc, char* argv[])
{
        size_t  len1 = 0;
        ssize_t len2;
        char*   line = NULL;
        std::vector<char*> F;
        while ((len2 = getline(&line, &len1, stdin)) != -1)
        {
                split_row(line, F, field_seperator);
                int NF = F.size();
//--- begin user program

+TemplateCFile

echo $program >> a.cpp

cat >> a.cpp <<+TemplateCFile

//--- end user program
; // avoid user program missing ;
                printf("\n");
        }
        if (line) free(line);
        if (ferror(stdin)) {
                perror("ferror(stdin)");
                return 1;
        }
        return 0;
}

+TemplateCFile

sed -i 's/\(field_seperator\[\]=\).*";/\1"'$field_seperator'";/g' a.cpp

gcc -O2 a.cpp -lstdc++ -o $output

exit $?


 

可以象awk一样写程序:

 

# 相当于 awk -F,  '{printf("%s\t%s\n", $1, $5)}'
# 使用 ',' 做列分隔符,输出第 1 和第 5 个字段,生成二进制可执行程序 myprog
./gencode.sh -F , -o myprog 'printf("%s\t%s\n", F[0], F[4])' 

 

我当初写这个生成器的原因是发现非常简单的 awk 程序也比 C 慢 40 倍,以为这是本质上的性能差距,后来才发现不是

 

对这个简单的程序,使用awk更方便更安全,也不比C慢,但是一旦碰到其它类似问题而 awk 解决不了,这种模式就可以派上用场了。

 

分享到:
评论
6 楼 七猫 2010-02-05  
可能用php+smarty会生成更容易懂的代码。
或者用python模板。
5 楼 febird 2010-02-05  
mikeandmore 写道
RednaxelaFX 写道
话说*-nix上还有不少人用m4,不知道楼主有没有玩过?

这东西早就该pia飞了。。。实在太麻烦了。。。


的确,如飞必要,还是别用
4 楼 febird 2010-02-05  
RednaxelaFX 写道
话说*-nix上还有不少人用m4,不知道楼主有没有玩过?


看过一点,m4 语法本身很简单,但是 m4 折衷基于宏扩展的语言,在大部分时候,就像大牛说的:导致的问题似乎比解决的问题更多
3 楼 RednaxelaFX 2010-02-05  
mikeandmore 写道
RednaxelaFX 写道
话说*-nix上还有不少人用m4,不知道楼主有没有玩过?

这东西早就该pia飞了。。。实在太麻烦了。。。

嘿嘿这反应跟我一样……但当我知道GemStone的GemStone/S(一种Smalltalk实现,内建OODB)和MagLev(基于前者的Ruby实现)有一大部分是用m4写的的时候,我震精了 =_=|||
2 楼 mikeandmore 2010-02-05  
RednaxelaFX 写道
话说*-nix上还有不少人用m4,不知道楼主有没有玩过?

这东西早就该pia飞了。。。实在太麻烦了。。。
1 楼 RednaxelaFX 2010-02-05  
话说*-nix上还有不少人用m4,不知道楼主有没有玩过?

相关推荐

Global site tag (gtag.js) - Google Analytics