- 浏览: 491507 次
- 性别:
- 来自: 上海
文章分类
最新评论
-
hypercube:
markin'
配置D语言编程环境 -
qiezi:
qiezi 写道yangyang_08 写道1 ...
我的编程语言学习经历 -
qiezi:
yangyang_08 写道1、现在如果做并发服务器,楼主选用 ...
我的编程语言学习经历 -
yangyang_08:
1、现在如果做并发服务器,楼主选用什么样的语言架构?2、lua ...
我的编程语言学习经历 -
dearplain:
我也是语言爱好者,不过我一直坚持使用c。
我的编程语言学习经历
借助D语言新的mixin表达式,可以完成一些代码生成功能,比如:
下面的大段代码演示了另一个功能,编译期字符串解析:
只需要编译它,就可以在编译期把字符串"a bc /a\\\\34/ \"bbc\" s 32 33 abv"解析为标记。
上面的代码全部使用模板来完成,实现极其复杂,而且无法在动态代码中重用,所以D 1.006加入了编译期执行方法,让这类代码可以在编译期和执行期都可以使用,不过目前为止,仅有小部分代码可以这样,但这会是它的大方向。
结合编译期生成和编译期执行这2项技术,可以完成一些复杂的编译器功能,一个理想的工作方式如下:
大概是这样的工作方式,在编译期就可以检查出SQL和IDL字符串的语法。
template attr_accessor(T, char[] name){ mixin(" private T _" ~ name ~ "; public " ~ name ~ "(){ return _" ~ name ~ "; } public " ~ name ~ "(T v){ _" ~ name " = v; } "); } class Foo{ mixin attr_accessor!(int, "bar"); } void main(){ auto foo = new Foo; foo.bar = 3; writefln(foo.bar); }
下面的大段代码演示了另一个功能,编译期字符串解析:
import std.metastrings; template drop_white(char[] s){ static if (s.length && (s[0] == ' ' || s[0] == '\t' || s[0] == '\r' || s[0] == '\n')) const char[] drop_white = s[1..$]; else const char[] drop_white = s; } template drop_comment(char[] s){ static if (s.length >= 2 && (s[0] == '/' && s[1] == '*')) const char[] drop_comment = scan_comment_end!(s[2..$]); else const char[] drop_comment = s; } template scan_comment_end(char[] s){ static if (s.length >= 2){ static if (s[0] == '*' && s[1] == '/') const char[] scan_comment_end = s[2..$]; else const char[] scan_comment_end = scan_comment_end!(s[2..$]); }else{ pragma(msg, "Failed to scan comment end"); static assert(false); } } template Token(char[] t, char[] v, char[] r){ const char[] type = t; const char[] value = v; const char[] remain = r; static if (t != "eof") alias next_token!(r) next; } template is_digit(char c){ const bool is_digit = c >= '0' && c <= '9'; } template is_letter(char c){ const bool is_letter = c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z'; } template get_token(char[] s){ static if (s.length == 0 || s[0] == '\0'){ const char[] type = "eof"; const char[] value = ""; const char[] remain = ""; }else static if (s[0] == '_' || is_letter!(s[0])){ alias parse_id!(s) token; const char[] type = "id"; const char[] value = token.first; const char[] remain = token.second; }else static if (s[0] == '"'){ alias parse_string!(s) token; const char[] type = "string"; const char[] value = token.first; const char[] remain = token.second; }else static if (is_digit!(s[0])){ alias parse_number!(s) token; const char[] type = "number"; const char[] value = token.first; const char[] remain = token.second; }else static if (s[0] == '/'){ alias parse_regexp!(s) token; const char[] type = "regexp"; const char[] value = token.first; const char[] remain = token.second; }else{ pragma(msg, "Can't parse token from: " ~ s); static assert(false); } debug pragma(msg, "Get token: " ~ value); } template parse_id(char[] s){ static if (s.length && (s[0] == '_' || is_letter!(s[0]) || is_digit!(s[0]))){ alias parse_id!(s[1..$]) id; const first = s[0..1] ~ id.first; alias id.second second; }else{ const char[] first = ""; alias s second; } } template parse_string(char[] s){ static if (s[0] == '"') alias scan_string_end!(s[1..$]) parse_string; else{ pragma(msg, "Failed to parse string"); static assert(false); } } template parse_number(char[] s){ static if (s.length && is_digit!(s[0])){ alias parse_number!(s[1..$]) number; const char[] first = s[0..1] ~ number.first; const char[] second = number.second; }else{ const char[] first = ""; const char[] second = s; } } template parse_regexp(char[] s){ static if (s.length && s[0] == '/') alias scan_regexp_end!(s[1..$]) parse_regexp; else{ pragma(msg, "Failed to parse regexp"); static assert(false); } } template scan_regexp_end(char[] s){ static if (s.length){ static if (s[0] == '/'){ alias pair!("", s[1..$]) scan_regexp_end; }else static if (s.length >= 2 && s[0] == '\\'){ alias scan_regexp_end!(s[2..$]) r; const char[] first = escape!(s[1]) ~ r.first; const char[] second = r.second; }else{ alias scan_regexp_end!(s[1..$]) r; const char[] first = s[0..1] ~ r.first; const char[] second = r.second; } }else{ pragma(msg, "Failed to parse regexp: " ~ s); static assert(false); } } template scan_string_end(char[] s){ static if (s.length){ static if (s[0] == '"') alias pair!("", s[1..$]) scan_string_end; else static if (s.length >= 2 && s[0] == '\\'){ alias scan_string_end!(s[2..$]) s; alias pair!(escape!(s[1]) ~ r.first, r.second) scan_string_end; }else{ alias scan_string_end!(s[1..$]) string; const char[] first = s[0..1] ~ string.first; const char[] second = string.second; } }else{ pragma(msg, "Failed to parse string"); static assert(false); } } template escape(char c){ static if (c == 'n') const char[] escape = "\n"; else static if (c == 't') const char[] escape = "\t"; else static if (c == 'r') const char[] escape = "\r"; else static if (c == '\\') const char[] escape = "\\"; else{ pragma(msg, "Failed to escape char '" ~ std.metastrings.ToString!(c) ~ "'"); static assert(false); } } template next_token(char[] s){ static if (s.length == 0){ const char[] type = "eof"; const char[] value = ""; const char[] remain = ""; }else{ const char[] comment_and_white_dropped = drop_comment!(drop_white!(s)); static if (s.length != comment_and_white_dropped.length){ alias next_token!(comment_and_white_dropped) t; }else{ alias get_token!(s) t; } alias t.type type; const char[] value = t.value; const char[] remain = t.remain; } static if (type != "eof") alias next_token!(remain) next; } template pair(char[] F, char[] S){ alias F first; alias S second; } import std.stdio; template output_token(alias T){ static if (T.type != "eof"){ pragma(msg, T.type ~ ": " ~ T.value); alias output_token!(T.next) output_token; } } template output(char[] token_parser, char[] source){ mixin("alias " ~ token_parser ~ "!(source) parser;"); alias output_token!(parser) output; } mixin output!("next_token", "a bc /a\\\\34/ \"bbc\" s 32 33 abv");
只需要编译它,就可以在编译期把字符串"a bc /a\\\\34/ \"bbc\" s 32 33 abv"解析为标记。
上面的代码全部使用模板来完成,实现极其复杂,而且无法在动态代码中重用,所以D 1.006加入了编译期执行方法,让这类代码可以在编译期和执行期都可以使用,不过目前为止,仅有小部分代码可以这样,但这会是它的大方向。
结合编译期生成和编译期执行这2项技术,可以完成一些复杂的编译器功能,一个理想的工作方式如下:
alias BNF!(import("ebnf.bnf")) EBNF; alias EBNF!(import("sql92.ebnf")) SQL; // 插入更多生成代码,或者是利用mixin生成。 User[] users = SQL!("select * from users where status = ?", 1); alias EBNF!(import("idl.ebnf")) IDL; mixin IDL!("interface X{} interface Y: X{}");
大概是这样的工作方式,在编译期就可以检查出SQL和IDL字符串的语法。
评论
3 楼
qiezi
2007-02-27
混淆倒是不容易。
你后面说的这个“Walter 应该把可以解释执行的代码范围放宽”,目前看来他应该正在做这件事。1.007比1.006多出来的功能里面主要就是这部分。
你后面说的这个“Walter 应该把可以解释执行的代码范围放宽”,目前看来他应该正在做这件事。1.007比1.006多出来的功能里面主要就是这部分。
2 楼
oldrev
2007-02-26
编译期执行是好东西,不过我觉得应该添加一个关键字:eval,让它表示在编译器执行代码求值,避免编译器混淆出错,如:
其次 Walter 应该把可以解释执行的代码范围放宽,我个人认为只要编译器看得到所需源代码就应该允许编译期执行。
int sqr(x) { return x*x; } const int foo = eval(sqr()); //编译时执行 const int bar = sqr();
其次 Walter 应该把可以解释执行的代码范围放宽,我个人认为只要编译器看得到所需源代码就应该允许编译期执行。
1 楼
ideage
2007-02-25
真是个 理想工作方式.
更理想的是动态语言嵌入了.
更理想的是动态语言嵌入了.
发表评论
-
D语言模板和编译期执行
2012-07-29 00:15 0D语言模板继承了C++模板的基本用法,在其上做了相当多扩充,近 ... -
Generator
2008-04-09 13:46 1975几种并发编程模型开销(从大到小): Process > ... -
lambda之路...
2007-11-09 22:57 2838DMD最近的版本号加入了闭包,感觉非常有用,虽然有些背后动作, ... -
像Erlang一样写D程序
2007-09-15 10:23 6696琢磨了好久,一直没时间来做它。在讨论这个问题的时候就已经有这想 ... -
[D语言] qsort的尴尬
2007-05-06 21:31 5039phobos里面在stc.c.stdlib里提供了qsort, ... -
强类型数值计算
2007-04-10 21:45 4669以前曾经讨论过使用typedef来完成强类型的数值计算,最终遇 ... -
简单的单元测试框架
2007-04-10 21:20 3115做了个简单的单元测试框架,只算个毛坯,遇到一些问题。 1、由 ... -
仿STL的vector,写了一组array操作方法。
2007-04-05 23:55 11942文档从MSDN抄过来的,稍稍改了一下。 module ar ... -
编译期执行的效率
2007-03-15 15:58 4181写了一个编译期执行的fibonacci模板: templ ... -
如何获得一个方法的名字?
2007-01-15 19:24 3455在D语言中,一个方法你可以得到它的指针(函数指针或委托),但不 ... -
D语言的函数编程
2007-01-07 11:17 3816前阵子论坛上有人问我D语言做函数编程怎样,老实说我没怎么想过这 ... -
D语言和python的差异
2007-01-07 10:12 6510这2个语言的比较怪怪的,我最近转换了一些twisted的源文件 ... -
从简单测试看D数组内存分配策略
2007-01-07 09:43 3196D语言动态数组可以在运行期改变大小,这和C++的vector相 ... -
DMD 0.178发布
2006-12-24 15:32 4560What's New for D 0.178 ... -
GDC 0.20发布
2006-12-17 14:35 2759引用 * Updated to DMD 0.177 * Fix ... -
DMD 0.177发布
2006-12-09 18:47 2240没什么亮点,BUG修复得也不多,BUG数量始终保持在250-2 ... -
DMD 0.176发布
2006-12-03 14:22 3027引用 What's New for D 0.176 Dec ... -
D语言的成员函数模板
2006-12-02 20:29 3040DMD 0.166 特性列表中有一条: * ncorp ... -
D语言 在栈上分配对象 以及 无需GC拖管对象
2006-11-28 13:18 2763一、栈上分配对象 C++可以轻易实现在栈上和堆上分配对象,例 ... -
打算把twisted移植到D语言上
2006-11-26 20:14 4174twisted是一个优秀的python网络开发库,以前用它做过 ...
相关推荐
第10章 早期(编译期)优化 10.1 概述 10.2 Javac编译器 10.2.1 Javac的源码与调试 10.2.2 解析与填充符号表 10.2.3 注解处理器 10.2.4 语义分析与字节码生成 10.3 Java语法糖的味道 10.3.1 泛型与类型擦除...
一个对象的生命期包括三个阶段:创建对象、对象的引用和释放对 象 。 1.8.3 创建对象 创建对象包括声明、实例化和初始化三方面的内容。通常的格式为 : 1. 声明对象 对象声明实际上是给对象命名,也称定义一个实例...
原型化开发方法包括生成原型和实现原型两个步骤。(×) 6. 面向对象的开发方法包括面向对象的分析、面向对象的设计和面向对象的程序设计。( √) 7. 软件危机的主要表现是软件的需求量迅速增加,软件价格上升。(×)...
张晓冬 等编著 )和《16/32 位微机原理、汇编语言及接口技术》(作者: 钟晓捷 陈涛 ,机械工业出版社 出版)等,可以在较大型的科技书店里查找或者直接从网上订购。 6. 初学者到底是应该先学C还是汇编? ...
本书配套光盘提供了书中所有示例程序的可执行文件、工程文件和完整源代码,以方便读者编译、调试示例程序。 本书主要面向对direct3d三维图形程序设计感兴趣的编程人员、游戏开发人员以及可视化仿真工程技术...
近几年一直在跟踪.NET技术的发展,积极从事.NET技术文档和图书的翻译工作。 目录 封面 -12 封底 572 前言 -9 目录 -6 第1章 C语言编程 1 1.1 创建C程序 1 1.1.1 编辑 1 1.1.2 编译 2 1.1.3 链接 2 1.1.4 执行 ...
Coalesys PanelBar + R.a.d Treeview +Xml 构建的Asp.net 菜单和权限管理模块 突破屏蔽限制,自己的网站使劲弹新IE窗口 对页面SCROLLING的CSS不能生效原因 .Net 中IE使用WinForm控件的使用心得。 动态加载用户控件的...
的 Android SDK 提供了在 Android 平台上使用 JaVa 语言进行 Android 应用开发必须的工具和 API 接口。 特性 • 应用程序框架 支持组件的重用与替换 • Dalvik Dalvik Dalvik Dalvik 虚拟机 专为移动设备优化 • ...
o 4.5 我可否用括号来强制执行我所需要的计算顺序? o 4.6 可是 && 和 || 运算符呢?我看到过类似 while((c = getchar()) != EOF && c != '\n') 的代码 …… o 4.7 我怎样才能理解复杂表达式?``序列点" 是什么?...
执行期类型信息(RTTI) 动态生成(Dynamic Creation) 异常处理(Exception Handling) Template Template Functions Template Classes Template的编译与链接 第3章 MFC六大关键技术之仿真 MFC类层次结构 Frame 1...
执行期类型信息(RTTI) 动态生成(Dynamic Creation) 异常处理(Exception Handling) Template Template Functions Template Classes Template的编译与链接 第3章 MFC六大关键技术之仿真 MFC类层次结构 Frame 1...
执行期类型信息(RTTI) 动态生成(Dynamic Creation) 异常处理(Exception Handling) Template Template Functions Template Classes Template的编译与链接 第3章 MFC六大关键技术之仿真 MFC类层次结构 Frame 1...
NEAT 程序一般执行过程 ..................................................................................................................... 20 第四章 窗口 ................................................
3.5 我可否用括号来强制执行我所需要的计算顺序? . . . . . . . . . . 14 3.6 可是&& 和|| 运算符呢?我看到过类似while((c = getchar()) != EOF && c != ’nn’) 的代码⋯⋯ . . . . . . . . . . . . . . . . . . ...
文将对 Linux™ 程序员可以使用的内存管理技术进行概述,虽然关注的重点是 C 语言,但同样也适用于其他语言。文中将为您提供如何管理内存的细节,然后将进一步展示如何手工管理内存,如何使用引用计数或者内存池来半...
a(D0),b(D1),c(D2),d(D3),e(D4),f(D5),g(D6),h(D7), 相应 8 个发光二极管正好与单片机一个端口 Pn 的 8 个引脚连接,这样单片机就可以通过引脚输出高 低电平控制 8 个发光二极的亮与灭,从而显示各种数字和符号;...