随笔- 26  文章- 0  评论- 10 
2009年7月17日
 1、./configure 脚本生成 自定义宏(Defining C Preprocessor Symbols):
     在 configure.in,通过 AC_DEFINE([STUDY],[yes],[define test]) 定义。 这个例子中定义个 STUDY的宏,值为 yes。执行 autoreconf ,然后configure后,输入的config.h中,基本就是下面的样子:
/* define test */
#define STUDY yes

     重点: gnu风格的程序,通过 configure & make 编译程序。configure分析系统环境,并保存结果,供源代码使用。AC_DEFINE 是保存结果的方式之一。

2、./configure 使用 --with-package功能: 
     AC_ARG_WITH (package, help-string, [action-if-given], [action-if-not-given]) 有4个参数,参考官方说明,比较容易理解。但是有点小麻烦,如--with-package=ABC,如果获取 '='后面的值,成为一个问题。看官方例子:

AC_ARG_WITH([readline],
    [AS_HELP_STRING([
--with-readline],
        [support fancy command line editing @
<:@default=check@:>@])],
    []
,
    [with_readline
=check])

LIBREADLINE
=
AS_IF([test 
"x$with_readline" != xno],
    [AC_CHECK_LIB([
readline], [main],
    [AC_SUBST([LIBREADLINE]
, ["-lreadline -lncurses"])
        AC_DEFINE([HAVE_LIBREADLINE]
, [1],
             [Define 
if you have libreadline])
    ]
,
    [
if test "x$with_readline" != xcheck; then
        AC_MSG_FAILURE(
            [
--with-readline was given, but test for readline failed])
    fi
    ]
, -lncurses)])

     其中 with_readline=check  和 [test "x$with_readline" != xno] 两行说明,可以通过 $with_<pakcage> shell变量,来获取命令行中的值(= 后面的部分)。经过实践:
               如果没有指定 --with-<package>,则 $with_<package>为空,
               如果指定 --without-<package>,则 $with_<package>为no
               如果指定 --with-<package>,则 $with_<package>为yes,
               如果指定 --with-<package>=ABC,则 $with_<package>为'ABC',
    重点: 如何通过命令行,对源代码配置进行适当的配置,$with_<package> 之类的参数提供一种沟通方式,让编译者控制源代码的生成。当然这个也需要用到 AC_DEFINE之类的命令。

posted @ 2009-07-17 23:25 thh 阅读(188) 评论(0) 编辑
2008年5月4日

1、 Insert/Remove 必须在 SubmitChanges,才能生效,并且SubmitChanges自动创建事务。在写数据库相关模块时,是否应该调用 SubmitChanges了?如果在每次执行数据库相关操作调用,那么众多事务,效果等于不使用事务。

2、由于插入是Pending的,所以不能及时得到 Id。所有对象都必须是关联的,否则无法通过Id实现操作。

3、为什么一定要先执行Select,然后才能执行Update/Remove了?Hibernate 还有ExecuteUpdate之类的方法,为什么Linq不能提供一个了?

posted @ 2008-05-04 21:31 thh 阅读(44) 评论(1) 编辑
2008年4月9日

     看了一年左右的设计,发现做出一个优秀的界面设计,还是不太容易。Form/Control的设计方案、MVC、MVP等等,纷繁复杂。让人迷失在众多概念当中,无法自拔。所以先收集一些文章,慢慢研究。

Interactive Application Architecture Patterns
An Introduction to the Model-View-Controller, Model-View-Presenter, and Presentation-Abstraction-Control Patterns
http://ctrl-shift-b.blogspot.com/2007/08/interactive-application-architecture.html

GUI Architectures
There have been many different ways to organize the code for a rich client system. Here I discuss a selection of those that I feel have been the most influential and introduce how they relate to the patterns.
http://martinfowler.com/eaaDev/uiArchs.html

上篇作者提到的参考实例:
http://codebetter.com/blogs/jeremy.miller/archive/2007/05/21/thoughts-rants-and-arguments-my-devteach-2007-rollup.aspx

Application Architecture for .NET: Designing Applications and Services
http://msdn2.microsoft.com/en-us/library/ms978340.aspx

CodeProject上关于Model View Persenter还有好多文章,大多都是类似 View Interface之类的概念。看完《Interactive Application Architecture Patterns》后,比较了众多MVC模式,发现microsoft也再搞View Interface模式,比martinfowler的MVP还多了点发展,并且还推出了Smart Client Factory 和Web Client Factory那个方便的东东。

posted @ 2008-04-09 22:42 thh 阅读(138) 评论(0) 编辑
2008年4月6日

使用win 2003的机器,好不容易装上个Live Writer啊!

网上有人介绍下在一个.msi 的安装包,然后直接安装。这是一个办法,老外写的,提供的安装包也是英文的,不方便。

更方便的办法是下载2007简体中文版本的msi,然后windows update 一下,方便很多阿。

posted @ 2008-04-06 00:38 thh 阅读(155) 评论(0) 编辑
2008年1月31日

LR 剖析器

[转自维基百科]

LR 剖析器是一种由下而上(bottom-up)的上下文无关语法剖析器。LR 意指由左(Left)至右处理输入字串,并以最右边优先衍生(Right derivation)的推导顺序(相对于 LL 剖析器)建构语法树。能以此方式剖析的语法称为 LR 语法。而在 LR(k) 这样的名称中,k 代表的是剖析时所需前瞻符号(lookahead symbol)的数量,也就是除了目前处理到的输入符号之外,还得再向右参照几个符号之意;省略 (k) 时即视为 LR(1),而非 LR(0)。


  由于LR 剖析器尝试由剖析树的叶节点开始,向上一层层透过文法规则的化简,最后推导回到树的根部(起始符号),所以它是一种由下而上的剖析方法。许多编程语言使用 LR(1) 描述文法,因此许多编译器都使用 LR 剖析器分析源代码的文法结构。LR 剖析的优点如下:

  • 众多的编程语言都可以用某种 LR 剖析器(或其变形)分析文法。(C++是个著名的例外)
  • LR 剖析器可以很有效率的建置。
  • 对所有“由左而右”扫描源代码的剖析器而言,LR 剖析器可以在最短的时间内侦测到文法错误(这是指文法无法描述的字串)。


  然而 LR 剖析器很难以人工的方式设计,一般使用“剖析产生器(parser generator)”或“编译器的编译器(compiler-compiler, 产生编译器的工具)”来建构它。 LR 剖析器可根据剖析表(parsing table)的建构方式,分类为“简单 LR 剖析器(SLR, Simple LR parser)”、“前瞻 LR 剖析器(LALR, Look-ahead LR parser)”以及“正统 LR 剖析器 (Canonical LR parser)”。这些解析器都可以处理大量的文法规则,其中 LALR 剖析器较 SLR 剖析器强大,而正统 LR 剖析器又比 LALR 剖析器能处理更多的文法。著名的 Yacc 即是用来产生 LALR 剖析器的工具。


目录

[隐藏]

LR 剖析器的结构

圖一 以表格為主由下而上之剖析器的結構
图一 以表格为主由下而上之剖析器的结构

  以表格为主(table-based)由下而上的剖析器可用图一描述其结构,它包含:

  • 一个输入缓冲区,输入的源代码储存于此,剖析将由第一个符号开始依序向后扫描。
  • 一座堆栈,储存过去的状态与化简中的符号。
  • 一张状态转移表(goto table),决定状态的移转规则。
  • 一张动作表(action table),决定目前的状态碰到输入符号时应采取的文法规则,输入符号指的是终端符号(Terminals)与非终端符号(Non-terminals)。

剖析算法

  LR 剖析过程如下:

  1. 将结尾字符 $ 与起始状态 0 依序压入空堆栈,之后的状态与符号会被压入堆栈的顶端。
  2. 根据目前的状态以及输入的终端符号,到动作表中找到对应动作:
    • 移位(shift) sn:
      • 将目前的终端符号由输入缓冲区中移出并压入堆栈
      • 再将状态 n 压入堆栈并成为最新的状态
    • 化简(reduce) rm:
      • 考虑第 m 条文法规则,假设该文法的右边(right-hand side)有 X 个符号,则将 2X 个元素从堆栈中弹出
      • 此时过去的某个状态会回到堆栈顶端
      • 状态转移表中查找此状态遇到文法左边(left-hand side)的符号时的状态转移
      • 将文法左手边的符号压入堆栈
      • 将查找到的新状态压入堆栈
    • 接受,输入字串解析完成。
    • 无对应动作,此情形即为文法错误。
  3. 重复步骤二直到输入的字串被接受或侦测到文法错误。

 范例

考虑以下文法:

(1) E → E * B
(2) E → E + B
(3) E → B
(4) B → 0
(5) B → 1

待剖析的输入字串是:

1 + 1

动作表与状态转移表

LR(0) 剖析器使用的表格如下:

动作 状态转移
状态 * + 0 1 $   E B
0     s1 s2     3 4
1 r4 r4 r4 r4 r4    
2 r5 r5 r5 r5 r5    
3 s5 s6   acc      
4 r3 r3 r3 r3 r3      
5     s1 s2     7
6     s1 s2     8
7 r1 r1 r1 r1 r1      
8 r2 r2 r2 r2 r2      

动作表 用以表示目前状态遇到终端符号(包含结尾字符 $)的对应动作,字段中可能有三种动作:

  • 移位,记为 'sn',表示下个状态是 n
  • 化简,记为 'rm',表示使用第 m 条文法规则化简堆栈中的内容。
  • 接受,记为 'acc',表示剖析正确的完成,输入的字串被文法所定义的语言接受.

状态转移表 用以表示简化后的状态遇到非终端符号时的转移规则。

 剖析过程

  下表是剖析过程中的各步骤,堆栈的顶端在最右边,状态的转移与堆栈的化简都以上表为依据,而特殊字符 '$' 也被加到输入串的尾端表示结尾。

目前的状态 堆栈 输入 将采取的动作
0 $ 0 1+1$ Shift 2
2 $ 0 '1' 2 +1$ Reduce 5
4 $ 0 B 4 +1$ Reduce 3
3 $ 0 E 3 +1$ Shift 6
6 $ 0 E 3 + 6 1$ Shift 2
2 $ 0 E 3 + 6 '1' 2 $ Reduce 5
8 $ 0 E 3 + 6 B 8 $ Reduce 2
3 $ 0 E 3 $ Accept

范例说明

  剖析起始时堆栈会包含元素 $ 与 0:

[$ 0]


  剖析器首先从输入缓冲区看到符号 '1',根据动作表当状态 0 碰到终端符号 '1' 时采用移位动作 s2,即是将 '1' 从输入缓冲区中移出并推入堆栈,再将新的状态 2 也推入堆栈,这时堆栈会变成:

[$ 0 '1' 2]


(为避免终端符号与状态混淆,故堆栈中的终端符号都加上单引号区别)

  接着看到的终端符号是 '+',根据动作表无论状态 2 碰到任何终端符号,都执行 r5 动作(以第五条文法规则 B → 1 化简堆栈内容)。此化简的动作表示剖析器已经在堆栈中认出第五条文法规则的右手边部分,因此可以用该规则的左手边符号 B 取代。因为第五条文法的右边有一个符号,因此我们将两个元素(1 × 2 = 2)自堆栈弹出,此时会回到状态 0,再推入符号 B,并查找转移表中状态 0 遇到非终端符号 B 后的新状态。新的状态是 4,完成此步骤后的堆栈是:

[$ 0 B 4]


  由于上一个终端符号 '+' 尚未被处理,因此仍保留在输入缓冲区中。依据动作表,在状态 4 碰到 '+' 时做 r3 化简。根据第三条文法 E → B,我们将 4B 从堆栈弹出,回到状态 0。接着压入 E ,根据状态转移表,当状态 0 遇到非终端符号 E 时需转移至状态 3 ,因此将 3 压入堆栈:

[$ 0 E 3]


  继续尚未处理的符号 '+',当状态 3 遇到 '+' 时的对应动作是 s6,将 '+' 从输入中移出并压入堆栈,再将新的状态 6 也压入堆栈:

[$ 0 E 3 '+' 6]


  下一个符号是 '1',在状态 6 看到 '1' 时的动作是 s2,将 '1' 从输入中移出并压入堆栈,再将新的状态 2 也压入堆栈:

[$ 0 E 3 '+' 6 '1' 2]


  最后看到的输入符号是 $,状态 2 遇到 $ 时的动作是 r5,以第五条文法规则化简堆栈内容。此化简动作与第二步骤相似,堆栈弹出两个元素后回到状态 6,这时再压入符号 B 后会进入状态 8(根据状态转移表),因此也将 8 压入堆栈:

[$ 0 E 3 '+' 6 B 8]


  在状态 8 看到符号 $ 时剖析器会继续化简,根据动作表执行 r2 化简动作,采用第二条文法规则 E → E + B 简化堆栈。由于该规则的右手边有三个符号,故从堆栈中弹出六个元素。这时回到状态 0,将规则左边的符号 E 推入堆栈后,进入新状态 3(根据状态转移表),将之压入后堆栈为:


[$ 0 E 3]

  最后在状态 3 看到符号 $,对应的动作是 acc,表示剖析顺利完成。

 建构 LR(0) 剖析表

 LR(0) 项目(Items)

  建构剖析表的过程须使用 LR(0) 项目(以下简称为“项目”),这些项目是在文法规则的右手边插入一个特殊的符号“‧”所产生。例如文法 E → E + B 有下列四个对应的项目:

E → ‧ E + B
E → E ‧ + B
E → E + ‧ B
E → E + B ‧

  若文法规则的形式是 A → ε ,则对应的唯一项目是:

A → ‧

  建立项目的用意是要决定剖析器的状态,例如 E → E ‧ + B 的意义是“剖析器已经在输入的符号中认出 E 的部分,目前正等著看到一个 '+' 符号与接续的 B 的部份”。


结论:LR(0)项目是由文法规则所产生



项目集合

  在一般的情形中,剖析器不能预知未来要用哪一条文法规则来化简堆栈内容,因此很难以单一个项目决定状态。例如以下文法:

E → E + B
E → E * B

  当剖析器认出堆栈中的 E 部分时,它无法预测未来会继续看到 '+' 或 '*',因此这时的状态须以两个项目表示:

E → E ‧ + B
E → E ‧ * B

  故我们使用项目的集合 { E → E ‧ + B, E → E ‧ * B } 来表示“剖析器认出 E 并期待 + B* B”的状态。


结论:LR(0)项目可以形成集合并描述剖析过程的状态



项目集合的封闭集

  如前段叙述,剖析器总是期待在下个输入中看到项目中的 '‧' 之后的符号。如果 '‧' 之后的符号是非终端符号,则应加入该符号所推演出的文法规则,如此才能正确的描述状态。例如规则:

E → E + B
B → 0
B → 1

  当我们来到状态 E → E + ‧ B 时,剖析器期待看到非终端符号 B,而 B 又可推演为终端符号 01。因此这时的状态应表示为:

E → E + ‧ B
B → ‧0
B → ‧1

即是“已辨认出 E + 部分,目前期待看到 B,而 B 也就是 '0' 与 '1'”之意。此现象可以描述为:

若项目集合中包含 A → x‧By 形式的项目,其中 B 为非终端符号,则对所有的文法规则 B → w 而言,B → ‧w也会被加入项目集合中。

  每个项目集合都应该以此规则扩充,将潜在的项目加到集合中直到所有在 ‧ 之后的非终端符号都处理过。如此所产生的新集合称作该项目集合的“封闭集”,符号的表示为 closure(I) ,其中 I 表示原项目集合。剖析过程中的各种状态即是由这些封闭集所构成。


结论:项目的封闭集才能完整的描述剖析过程的状态



扩充文法

  在决定状态间的转移前,我们必须先加入一条扩充文法:

(0) S → E

  其中 S 是新的起始符号(start symbol)而 E 是原先的起始符号。考虑以下文法:

(1) E → E * B
(2) E → E + B
(3) E → B
(4) B → 0
(5) B → 1

  加入扩充文法后,我们使用下列规则来决定项目集合与状态:

(0) S → E
(1) E → E * B
(2) E → E + B
(3) E → B
(4) B → 0
(5) B → 1


结论:建构剖析表前必须先加入扩充文法



寻找可到达的集合与之间的转移

  建构剖析表的第一步是找出封闭集合之间的转移。封闭集可以视为自动机中的状态,而状态间的转移则由终端符号与非终端符号决定。起始状态是由扩充的第 0 条文法规则对应的项目所形成的封闭集:

Item set 0
S → ‧ E
E → ‧ E * B
E → ‧ E + B
E → ‧ B
B → ‧ 0
B → ‧ 1

  集合中的第一个项目是该集合的核心,透过集合的封闭规则,我们加入其他项目补足集合使其封闭。这组封闭集合是第一个状态(I0),现在我们要找出这组状态可能的转移情形。

 建构动作表与状态转移表

 关于 LR(0) 与 SLR、LALR 剖析

[编辑] 表格中的冲突

[编辑] LR(0) 的例子

   E->E+T/T
T->T*F/F
F->id
   S->AA
A->aA/b

[编辑] 参考资料

posted @ 2008-01-31 13:45 thh 阅读(221) 评论(0) 编辑
2007年10月9日
摘要: MVP模式实现了View Interface,让Controller代码从View层很好的分离出来,逻辑也更清晰。这个和传统的Page_Load的面条代码相比,有很明显的进步。采用MVP模式之后,Page_load里的代码明显减少了。对于网站开发而言,你可以在dll里写出控制器代码和视图的接口了,以后页面的具体布局,风格也就可以少抄心很多了。但是新问题也产生了: 1、Presenter 中往往有好...阅读全文
posted @ 2007-10-09 11:53 thh 阅读(191) 评论(0) 编辑
2007年10月2日
摘要: 比较了一下创建记录的时间,和表空间的大小,首先创建了3个表:CREATETABLE[dbo].[Role]([Id][uniqueidentifier]NOTNULL,[Name][nvarchar](255)NULL,[Description][nvarchar](255)NULL,PRIMARYKEYCLUSTERED([Id]ASC))CREATETABLE[dbo].[RoleId]([I...阅读全文
posted @ 2007-10-02 15:29 thh 阅读(571) 评论(0) 编辑
2007年9月13日
摘要: Implementing the Singleton Pattern in C#原文:http://www.yoda.arachsys.com/csharp/singleton.htmlThe singleton pattern is one of the best-known patterns in software engineering. Essentially, a singleton i...阅读全文
posted @ 2007-09-13 14:38 thh 阅读(304) 评论(0) 编辑
2007年9月11日
摘要: 在给程序添加Nhibernate.dll引用后,居然出现:错误 MSB3095: 参数无效。区域性 ID 2155 (0x086B)不是受支持的区域性。在网上好多地方都没有找到解决办法,只好直接奋斗以下。 想了个歪主意,通过.net 2.0的配置控制台,把Nhibernate.dll添加到程序集缓存中,然后在项目中用应用GAC里的NHibernate,重新编译通过了。 怪问题.....阅读全文
posted @ 2007-09-11 17:21 thh 阅读(504) 评论(2) 编辑
2007年7月25日
摘要: 首先 在event filter 中选中loal module,enable,直到 mscorwks.dll被加载,然后执行 bp mscorwks!Assembly::Init,然后 g。当clr程序加载 assembly时,一般都会遇到上面设置的断点,这个时候就可以用机会使用 !bpmd ,给一些static 之类的类设置断点了。阅读全文
posted @ 2007-07-25 17:13 thh 阅读(257) 评论(0) 编辑