作者:Patrick Y. Ng
原文地址:http://forums.asp.net/7504/ShowPost.aspx
译者:Tony Qu
译者Blog:tonyqus.cnblogs.com

原文最后一次更新:2004年9月21日

本文被分成两部分:
1.“理解Session State模式”——帮助你理解三种Session State的不同之处
2. FAQ

1.理解Session State模式

存储位置
InProc:session在服务器中以活动对象方式存储(aspnet_wp.exe)

StateServer: session被序列化并保存在单独的aspnet_state.exe的内存中。StateServer能够运行在另一台服务器上

SQLServer: session被序列化并保存在SQL Server中

性能:
InProc:最快,但是session数据越多,web服务器上消耗的内存也越多,它可能影响性能。

StateServer:当存储基本类型(如string,integer等)数据时,在同一个测试环境中它比InProc慢15%。如果你存储大量对象,序列化和反序列化可能影响到性能

SQLServer:当存储基本类型(如string,integer等)数据时,在同一个测试环境中它比InProc慢25%。它也有与StateServer一样的序列化性能问题。

关于Out-of-Proc(OOP,非InProc)模式的性能提示
如果你使用OOP模式(即StateServer或SQLServer),session state中的序列化和反序列化对象将成为你的主要性能消耗之一。对于基本类型,ASP.NET通过一种内部优化方法来完成序列化和反序列化。(基本类型包括所有的数字类型(如Int, Byte, Decimal,String, DateTime, TimeSpan, Guid, IntPtr和UIntPtr等))

如果你有一个session变量(如一个ArrayList对象),且它不是一个基本类型,ASP.NET将使用BinaryFormatter来进行序列化和反序列化,那可能会相对慢一些。

所以出于性能考虑,最好使用上面列出的基本类型来存储所有的session state数据。例如,如果你需要存储两个东西,名字和地址,在session state中你既可以(方法a)使用两个string session变量来存储它们,也可以(方法b)创建一个内含两个string的类来保存它们,然后把这个类对象保存在一个session变量中。出于性能考虑,你应该选择方法a。

为了进一步理解这个主题,请看FAQ中的一个问题:“序列化和反序列化如何在SqlServer和StateServer模式下工作”

健壮性
InProc:如果工作者进程(aspnet_wp.exe)进行资源回收或者应用程序域(appdomain)重启动,session state就会丢失。这是因为session state是保存在一个应用程序域的内存空间中的。对配置文件(如web.config和machine.config)的修改或者/bin目录的任何改变(例如在你使用VS编译应用程序后产生了一个新的dll)都可能引起重启动,详细请见KB324772。在1.0中,也有一个bug可能引起工作者进程重启动,但这个bug在1.1中已经修复,见KB321792。

如果你使用的是IIS6.0,你可以在IIS Manager中找到Application Pools/DefaultAppPool,其中可以看到回收(Recycling)选项卡与性能(Performace)选项卡中是否有引起IIS工作者进程(w3svc.exe)停止工作的参数。

更多有关应用程序资源回收的内容,可以看我的另一篇FAQ:
http://www.asp.net/Forums/ShowPost.aspx?tabindex=1&PostID=232621

StateServer:解决了InProc模式的session state丢失问题。允许一个webfarm在中央服务器中存储session。只能在State Server上出现失败。

SQLServer:与StateServer相似。session state的数据在SQL Server重启后仍然保留着,你也可以按照KB311209的步骤使用SQL server failover cluster

警告
InProc:它不能在web garden模式下工作,因为在这个模式下会有多个aspnet_wp.exe在同一台机器上运行。建议在使用web garden使切换到State Server或SQL Server。仅在InProc模式下支持Session_End事件。

StateServer
- 在web farm中,请确认在所有的web服务器上有相同的<machineKey>。KB313091描述了如何设置它。
- 请确保你的对象是可序列化的。详见KB312112
- 为了在web farm中的不同web服务器上维护session state,IIS Metabase中的网站应用程序路径(如/LM/W3SVC/2)应该在所有的服务器上保持一致(大小写敏感)。详见KB325056

SQLServer
- 在1.0中有一个bug,如果你在连接字符串中指定integrity security(如"trusted_connection=true"或 "integrated security=sspi"),且你打开了asp.net的身份模拟,它将不会工作。这个问题在KB324479中有描述,不幸的是这份文档中的描述和原因部分是错误的。不过已经有一个QFE fix对它作了修复,这个fix将包含在1.0 sp3中。这个问题在1.1中已经修复了。
- 请确认你的对象是可序列化的,否则你的请求可能被挂住,详见KB312112。SQLServer模式的挂起问题已经在1.1中修复,KB324479的QFE fix也修复了这个问题。1.0 sp3也对这个问题作了修复。
- 为了在web farm中的不同web服务器上维护session state,IIS Metabase中的网站应用程序路径(如/LM/W3SVC/2)应该在所有的服务器上保持一致(大小写敏感)。详见KB325056

其他资源
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaspp/html/aspnetsessionstate.asp
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnbda/html/CachingArchch2.asp
http://www.411asp.net/home/tutorial/specific/web/sessions

2. FAQ问题列表
Q: session state在部分浏览器上工作,而在其他一些上不工作。为什么呢?
Q: 在InProc模式中,为什么我有时会丢失所有的session?
Q: session state在一些web服务器上工作,但是在其他服务器上不工作。
Q: 为什么session state不可用?
Q: 为什么session_end没有触发?
Q: 使用InProc模式时,为什么我的session变量频繁丢失?
Q: 在session超时或删除之后,为什么SessionID保持不变
Q: 为什么SessionID每一次请求都会改变
Q: Session.Abandon()和Session.Clear()有什么区别
Q: session的Timeout属性是一个滑动超时值吗?
Q: 我可以在ASP.NET和ASP之间共享session吗?
Q: 我可以在web应用程序(例如虚拟目录或者IIS的应用程序)间共享session state吗?
Q: 在session state中可以存储哪些类型的对象?
Q: 为什么我的请求在切换到SQLServer模式之后挂住了?
Q: 为什么Response.Redirect和Server.Transfer在Session_End中不工作?
Q: 在Session_End中,我可以获得一个有效的HttpSessionState对象和HttpContext对象吗?
Q: 在web service中如何使用session?
Q:我正在写一个HttpHandler,为什么session stae不工作?
Q: 我正在使用web farm,并且每当我重定向到其他服务器时,session state就会丢失?
Q: 如果使用cookieless,我该如何从一个HTTP页面重定向到一个HTTPS页面?
Q: session state有没有一个锁机制来安排对session的访问顺序?
Q: 我该如何检测一个session过期,然后重定向到另一个页面
Q: 在Session_End中,我尝试使用SQL做一些清理工作,但是失败了,请问为什么?
Q: 我使用的是SQLServer模式,为什么我的session不会过期
Q: 我有一个以htm为扩展名的frameset页面,并且我发觉其中包含的每个帧在第一次请求时都有一个不同的SessionID,这是为什么?
Q: 我将EnableSessionState设置为ReadOnly,但是在InProc模式下,我仍然可以修改session,为什么?
Q: 我将cookieless设置为true,在Redirect之后session变量丢失了,为什么?
Q: 将cookieless设置为true有哪些缺点
Q: 在InProc模式下,我用编程方式改变了session的超时时间,它触发了Session_End,为什么?
Q: 在SQLServer模式下,我可以把session state保存在除tempdb之外的数据库中吗?
Q: 如何防止将未加密的字符串放在我的连接字符串汇总?
Q: 在使用SQLServer模式时,我需要怎样的SQL权限?
Q: 我可以自己写定制的session state模式吗?
Q: 在SQLServer或StateServer模式下,序列化和反序列化如何工作?
Q: 我该如何让我的state server更安全?
Q: 我能否可以使用非global.asax中的处理程序来订阅SessionStateModule.End事件?
Q: 不同的应用程序可以把他们的session state保存在同一个SQL Server上的不同数据库中吗?

Q: session state在部分浏览器上工作,而在其他一些上不工作。为什么呢?
A: 估计你没有使用cookieless,你必须保证你的浏览器支持cookie。请参考这份KB:http://support.microsoft.com/default.aspx?scid=kb;EN-US;q316112

Q: 在InProc模式中,为什么我有时会丢失所有的session?
A: 请见理解session state模式的健壮性部分

Q: session state在一些web服务器上工作,但是在其他服务器上不工作。
A: 可能是机器名的问题,见http://support.microsoft.com/default.aspx?scid=kb;EN-US;q316112

Q: 为什么session state不可用?
A:
- 首先,检查web.config、machine.config和Page标签来确认你启用了session state
参考资料:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpconsessionstate.asp
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpgenref/html/cpconpage.asp
- 请注意session state并非在任何地方、任何时间都可以使用,它仅在HttpApplication.AcquireRequestState事件之后可用。例如,在 global.asax中的Application_OnAuthenticateRequest处理程序中,session state不可用
- 请确认System.Web.SessionState.SessionStateModule已包含在配置文件的< httpModules>节中。一个常见的例子是,出于性能考虑,SharePoint应用程序会把这个模块从web.config文件中移除,因此导致session不可用

Q: 为什么session_end没有触发?
A: 这是最常见的问题之一
1. 请记住session_end仅在InProc模式中可用
2. 关闭浏览器,session_end是不会触发的。HTTP是一种无状态协议,服务器没有办法知道你的浏览器是否已经关闭。
3. 当有n分钟(n=timeout值)的无操作或调用Session.Abandon时,Session_End才会触发
4. 对于情况1而言,Session_End将由一个后台线程触发,这表示:
a. Session_End中的代码使用工作者进程账号运行,如果你访问如数据库这样的资源时,可能会有权限问题。
b. 如果在Session_End中发生错误,程序不会通知发生了什么
5. 对于情况2而言,为了让Session_End触发,session state必须先存在。这意味着你必须在session state中存储一些数据,并且已经完成了至少一个请求
6. 还是对于情况2而言,Session_End仅在被丢弃的session被找到的时候才会触发。这样的话,如果你在同一个请求中创建并丢弃一个 session,由于session没有被保存,因此也不会被找到,Session_End将不会被调用。这是v1.0和v1.1中的bug。

Q: 使用InProc模式时,为什么我的session变量频繁丢失?
A: 有可能是应用程序资源回收引起的,见http://support.microsoft.com/default.aspx?scid=kb;en-us;Q316148
在v1.0中有一个bug可能会导致工作者进程重启动。在v1.1和v 1.0sp2中已经修复。见http://support.microsoft.com/default.aspx?scid=kb;EN-US;321792

关于应用程序资源回收的详细信息,请见我的另一篇:FAQhttp://www.asp.net/Forums/ShowPost.aspx?tabindex=1&PostID=232621

Q: 在session超时或删除之后,为什么SessionID保持不变
A: 尽管在超时周期之后session state过期,sessionID将一直保持到浏览器session过期为止,也就是说,一个相同的sessionID可以有多次session超时,但是始终对应着一个相同的浏览器实例。

Q: 为什么SessionID每一次请求都会改变
A: 如果你的应用程序从未在session state中存储过数据。在这种情况下,那么每次请求都会创建一个新的session state(ID也是新的),但是不会被存储,因为里面什么数据都没有。

尽管如此,有两种例外可能产生相同的Session ID
- 如果用户使用相同的浏览器实例来请求另一个使用session state的页面,那么你每次获得的Session ID是相同的。详见“在session超时或删除之后,为什么SessionID保持不变?”
- 如果使用了Session_OnStart事件,即使session为空,asp.net也会保存session state。

Q: Session.Abandon()和Session.Clear()有什么区别
A: 主要的区别在于,如果你调用Session.Abandon(), Session_End将被触发(仅在InProcxi下适用),在下一个请求中,Session_Start触发。而Session.Clear()仅仅是清除数据,但没有删除session。

Q: session的Timeout属性是一个滑动超时值吗?
A: Session的Timeout是一个滑动过期时间,意思是一旦你的页面访问session state,过期时间就会向挪。注意,只要页面没有被禁用,在请求时页面就会自动访问session

Q: 我可以在ASP.NET和ASP之间共享session吗?
A:不可以。但是有一篇文章讲到了如何来绕过这个问题:http://www.msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaspp/html/ConvertToASPNET.asp

当然也有一些第三方解决方案。

Q: 我可以在web应用程序(例如虚拟目录或者IIS的应用程序)间共享session state吗?
A:不能。

Q: 在session state中可以存储哪些类型的对象?
A:这是由你使用的模式决定的
- 如果你使用的是InProc模式,存储在session state中的对象是活对象,那么你就可以存储你创建的任何对象
- 如果你使用的是SQLServer或State Server模式,当处理一个请求时,session state中的对象对象将被序列化和反序列化,所以请确认你的对象都是可序列化的,而它们的类都作了可序列化标记。如果没有,session state将不会成功存储。在v1.0中,有一个bug,当这个问题发生时,如果使用SQLServer模式,请求可能在不知情的情况下被挂起。挂起的问题在v1.1和v1.0 sp3中已经修复。KB324479的QFE fix也包含了对这一问题的修复。

更多信息请见:http://support.microsoft.com/directory/article.asp?ID=KB;EN-US;q312112

Q: 为什么我的请求在切换到SQLServer模式之后挂住了?
A:请看问题“在session state中可以存储哪些类型的对象?”的答案

Q: 为什么Response.Redirect和Server.Transfer在Session_End中不工作?
A:Session_End是在服务器内部触发的,它基于一个内部的计时器。因此,在事件触发时,与任何HttpRequest对象无关。这也是为什么Response.Redirect 和Server.Transfer不工作的原因。

Q: 在Session_End中,我可以获得一个有效的HttpSessionState对象和HttpContext对象吗?
A:  你可以获得httpSessionState对象,你可以使用'Session'来访问该对象。但是你无法访问HttpContext,因为这个事件和请求没有任何关系。

Q: 在web service中如何使用session?
A: 需要在调用方使用一些技巧,你必须保存web服务使用的cookie。请见关于HttpWebClientProtocol.CookieContainer的MSDN文档。

尽管如此,如果你是通过代理对象从你的页面调用web服务,由于架构限制,web服务和你的页面无法共享session state。

如果你通过redirect调用web服务,这是可以完成的

Q:我正在写一个HttpHandler,为什么session stae不工作?

A: 你的HttpHandler接口必须实现标记接口IRequiresSessionState或IReadOnlySessionState,方能使用session state。

Q: 我正在使用web farm,并且每当我重定向到其他服务器时,session state就会丢失?
A: 为了在web farm中的不同服务器之间维护session state,IIS Metabase中的网站应用程序路径(例如 /LM/W3SVC/2)应该在所有的web服务器上保持一致(大小写敏感)。详见KB325056

Q: 如果使用cookieless,我该如何从一个HTTP页面重定向到一个HTTPS页面?
A: 尝试使用下面的代码:
String originalUrl = "/fxtest3/sub/foo2.aspx";
String modifiedUrl = "https://localhost" + Response.ApplyAppPathModifier(originalUrl);
Response.Redirect(modifiedUrl);

Q: session state有没有一个锁机制来安排对session的访问顺序?
A:session state实现了读写锁定机制:
- 对session state有写权限(如<%@ Page EnableSessionState="True" %> )的页面或帧将获得这个session的写锁,直到请求结束。
- 对session state有读权限(如<%@ Page EnableSessionState="ReadOnly" %> )的页面或帧将获得这个session的读锁,直到请求结束。
- 读锁会阻塞写锁;读锁不会阻塞读锁;写锁会阻塞所有的读锁和写锁
- 这也是为什么当两个帧同时拥有session的访问权限时,一个帧必须等待另一帧先完成

Q: 我该如何检测一个session过期,然后重定向到另一个页面
A: 这是经常要遇到的问题,但不幸的是没有很简单的方法来完成它。我们将期待在一个主要版本中实现它。同时,如果你使用cookie,你可以在cookie中存储一个标志,这样你就可以区分新浏览器+新session及旧浏览器+过期session,下面的代码在session过期时会重定向到一个过期页面。
void Session_OnStart(Object sender, EventArgs e) {
    HttpContext context = HttpContext.Current;
    HttpCookieCollection cookies = context.Request.Cookies;

if (cookies["starttime"] == null) {
        HttpCookie cookie = new HttpCookie("starttime", DateTime.Now.ToString());
        cookie.Path = "/";
        context.Response.Cookies.Add(cookie);
    }
    else {
        context.Response.Redirect("expired.aspx");
    }
}

Q: 在Session_End中,我尝试使用SQL做一些清理工作,但是失败了,请问为什么?
A: 首先,session_End仅在InProc模式下支持。
第二,Session_End是用运行工作者进程(aspnet_wp.exe)的帐号运行的,这个账号可以在machine.config中指定。因此,在你的Session_End中,如果使用integrity security连接SQL,它将使用工作者进程账号身份连接,这可能会引起登录失败,这要看你的SQL安全设置了。

Q: 我使用的是SQLServer模式,为什么我的session不会过期
A: 在SQLServer模式下,session过期是由SQL Agent使用一个注册任务完成的,请确认你的SQL Agent是否已经运行。

Q: 我有一个以htm为扩展名的frameset页面,并且我发觉其中包含的每个帧在第一次请求时都有一个不同的SessionID,这是为什么?
A: 原因是你的frameset页面是一个htm文件而不是一个aspx页面

在通常情况下,如果一个frameset页为一个aspx文件,当你请求该页面时,会首先发请求给web服务器,你会收到一个asp.net session cookie(其中保存着session id),然后浏览器会为frame发送一个单独的请求,而每个请求将拥有相同的session id。

然而,因为你的页面是一个htm文件,第一个请求就不会获得任何session cookie,因为页面是由asp处理的而非asp.net,然后浏览器会为每个帧发送单独的请求。但是,这次每个单独的请求将不会持有任何 session id,这样的话每个帧将创建自己的session。这也是为什么你在每个帧中看到的session id都不同。最后一个请求将赢得胜利,因为它将覆盖前两个请求写入的cookie。如果你刷新一次,你将看到它们拥有了相同的session id。

这个行为是设计所决定的,简单的解决方法就是将frameset页面改称aspx
 
Q: 我将EnableSessionState设置为ReadOnly,但是在InProc模式下,我仍然可以修改session,为什么?
A: 尽管那些EnableSessionState被设置为ReadOnly,但是在InProc模式中,用户仍然可以修改session。唯一的区别在于session在请求中不会被锁住,这一限制是设计所决定的。对于这一点没有在msdn中提到我表示抱歉。

Q: 我将cookieless设置为true,在Redirect之后session变量丢失了,为什么?
A: 如果你使用的是cookieless,你必须使用相对路径(如../hello.aspx),而不是绝对路径(如/foo/bar/hello.aspx)。如果你使用的是绝对路径,ASP.NET不会将session id保存在url中。

Q: 将cookieless设置为true有哪些缺点
A: 设置cookieless=true表示一些潜在的规则,主要有:
1. 你不能在你的页面中使用绝对路径
2. 在http和https之间切换的话,你必须做一些额外的动作
3. 如果你的客户发送了一个链接到一个朋友,URL将包含session id,两个用户可以在同一时间使用相同的session id

Q: 在InProc模式下,我用编程方式改变了session的超时时间,它触发了Session_End,为什么?
A: 这是InProc的一个bug。如果你更改session的timeout值为另一个值,Session_End将被调用(但不会调用Session_Start)。我们期待在v2.0中能够修复这个错误。

Q: 在SQLServer模式下,我可以把session state保存在除tempdb之外的数据库中吗?
A: 是的。见KB311209。

Q: 如何防止将未加密的字符串放在我的连接字符串汇总?
A: 见sql trusted connection或者将连接字符串以加密数据形式保存在注册表中。详情请见,KB329250和KB329290。

Q: 在使用SQLServer模式时,我需要怎样的SQL权限?
A: 调用者需要对下面的存储过程拥有EXEC权限,
dbo.TempGetAppID
dbo.TempGetStateItem
dbo.TempGetStateItemExclusive
dbo.TempReleaseStateItemExclusive
dbo.TempInsertStateItemLong
dbo.TempInsertStateItemShort
dbo.TempUpdateStateItemLong
dbo.TempUpdateStateItemShort
dbo.TempUpdateStateItemShortNullLong
dbo.TempUpdateStateItemLongNullShort
dbo.TempRemoveStateItem
dbo.TempResetTimeout
在v1.1中,你也需要对下面的存储过程拥有EXEC权限
dbo.TempGetStateItem2
dbo.TempGetStateItemExclusive2

请注意存储过程的拥有者必须对session state表(dbo.ASPStateTempSessions和 dbo.ASPStateTempApplications)拥有SELECT/INSERT/UPDATE/DELETE 权限。通常,拥有者是执行installsqlstate.sql(或者持久版本,见KB311209)的帐号来安装sql session state需要的表、存储过程、数据库

也请注意,如果你的session state表在tempdb中(默认情况下)如果你对SQL Server进行资源回收,所有在这张表上的权限设置将丢失。

Q: 我可以自己写定制的session state模式吗?
A:(待翻译)

Q: 在SQLServer或StateServer模式下,序列化和反序列化如何工作?
A: (待翻译)

Q: 我该如何让我的state server更安全?
A:如果state server和web server运行在一台机器上,通过设置HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services/ aspnet_state/Param ters/AllowRemoteConnection的dword项为0,可以让state server仅在本地运行。这样就可以防止远程客户端连见到state server上。这一特性在v1.1中可用,在v1.0 sp3中也有。

state server必须受防火墙保护,以防止外部连接以保证真正安全。默认的端口是TCP 42424,你可以设置HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services/ aspnet_state/Param ters/Port来改变它。如果是本地模式,除了127.0.0.1以外,屏蔽所有外来连接;如果是远程模式,显式的禁用所有的地址,除了对wev服务器的连接。

使用IPSec是另一种保护state server的方式。

Q: 我能否可以使用非global.asax中的处理程序来订阅SessionStateModule.End事件?
A: 答案是否定的。当SessionStateModule触发End事件时,只有定义在global.asax中的方法才会被触发

这是出于安全原因考虑的才对此进行限制。假设asp.net允许用户使用的其他的处理程序来处理End事件。在这种情况下,用户通常使用一个页面方法作为处理程序,当你在事件订阅时传入处理程序,处理程序将与你的程序运行在的HttpApplication实例关联。请注意, HttpApplication实例会被回收来处理其他请求。这样的话,当End事件触发时,asp.net将调用处理程序,而与之关联的 HttpApplication实例已经被另一个请求所使用,这样的情况将引发各种各样的问题。为了避免这种危险,在v1.0中决定进调用 Global.asax中定义的方法。希望你们都可以忍受这一限制。

Q: 不同的应用程序可以把他们的session state保存在同一个SQL Server上的不同数据库中吗?
A: 答案是肯定的。详情请见:http://support.microsoft.com/default.aspx?scid=kb;EN-US;836680

posted @ 2006-10-24 22:10 Tony Qu 阅读(1307) | 评论 (1) | 编辑 收藏

2006年8月25日

Calculator.NET 2.3发布

科学计算器 2.3发布
简介
    支持表达式计算的科学计算器。完全可以替代Windows自带的计算器,使用起来更加人性化。支持变量保存、三角函数运算、指幂运算、角度弧度转换,除了Windows计算器的进制计算不支持外,其他的功能都已经实现。

关于我为什么要做这个计算器,请见 http://www.cnblogs.com/tonyqus/archive/2005/04/14/137792.html

What's NEW
1. 支持负号(原来使用@代替负号)
2. 在菜单中显示变量值
3. 支持弧度/角度切换
4. 支持两种视图模式:Full和Compact
5. 支持结果显示方式切换:Auto, Fixed, Scientific, Grouped
    以123445.12345为例
    Auto: 123445.12345
    Fixed: 123445.12
    Scientific: 1.234451E+005
    Grouped:  123,445.12
6. 在提示屏幕中显示实际的计算公式(替换所有变量)

Bug修正
1. 禁止用户输入#,否则可能出错
2. 修正ANS无法参与计算的问题

新版本采用Visual Studio 2005开发
不再提供基于Visual Studio.net 2003的更新版本,基于VS2003的最高版本为2.1

源代码下载地址: http://www.cnblogs.com/Files/tonyqus/Calculator.NET.v2.3.zip

如果有任何意见或者bug,请写在回复中,谢谢!

如果想了解该计算器的制作原理,请见 http://www.cnblogs.com/tonyqus/category/23590.html 中的文章
=============================Update on 2006.8.28==============================
请8月28日之前下载的朋友重新下载源代码,修正两个表达式显示的小问题
1. 未替换小写的变量为真实值
2. 未将大小写的ans替换为真实值

posted @ 2006-08-25 17:59 Tony Qu 阅读(392) | 评论 (2) | 编辑 收藏

2006年8月8日

Javascript:检测FlashPlayer版本的函数

function  getFlashVer() { // 获得flashplayer的版本 google
  var  f = "" ,n = navigator; 
  if  (n.plugins  &&  n.plugins.length) {
   for  ( var  ii = 0 ;ii < n.plugins.length;ii ++ ) {
    if  (n.plugins[ii].name.indexOf('Shockwave Flash') !=- 1 ) {
    f = n.plugins[ii].description.split('Shockwave Flash ')[ 1 ];
     break ;
   }
  }
 }  else   if  (window.ActiveXObject) {
   for  ( var  ii = 10 ;ii >= 2 ;ii -- ) {
    try  {   
     var  fl = eval( " new ActiveXObject('ShockwaveFlash.ShockwaveFlash. " + ii + " '); " );
     if  (fl) {f = ii  +  '. 0 ';  break ; }
   }
    catch (e) {}
  }
 }
 document.write( " 您的FlashPlayer版本为 <b> " + f + " </b> " ); 
}

posted @ 2006-08-08 11:47 Tony Qu 阅读(83) | 评论 (0) | 编辑 收藏

2006年6月29日

关于VS2005中的Code Snippets Manager的问题及解决

Code Snippets Manager是VS2005专门用来管理代码块智能感知的工具。

然而,使用它并没有预想中的那么顺利,特别是在做过多次目录添加和删除之后,可能出现添加在列表中的目录无法在智能感知列表中显示出来的情况;甚至会出现列表当中明明没有这个目录,却也添加不进去的情况,它总是认为这个目录已经在列表中存在。为了解决这个问题,我对它的存储方式作了一些研究,并跟踪了相关的注册表和文件变化,下面是我的研究结果。

Code Snippets Manager主要在三个地方保存信息:

1. HKEY_CURRENT_USER/Software/Microsoft/VisualStudio/8.0/Open Find/Microsoft Visual Studio/Settings/Code Snippets Directory/File Name MRU/Value

这是一个REG_MULTI_SZ 类型的值,可以用来存储多个字符串,可以看作是一个字符串数组,这里用来存储路径,用回车作为分隔符,在我的机器上,它的值是这样的。

C:/Documents and Settings/tonyqus/My Documents/MSDN/Visual C# 2005 Code Snippets/filesystem
C:/Documents and Settings/tonyqus/My Documents/MSDN/Visual C# 2005 Code Snippets/datatypes
C:/Documents and Settings/tonyqus/My Documents/MSDN/Visual C# 2005 Code Snippets/database
C:/Documents and Settings/tonyqus/My Documents/code1
C:/Documents and Settings/tonyqus/My Documents/MSDN/Visual C# 2005 Code Snippets/
C:/Program Files/Microsoft Visual Studio 8/VC#/Snippets/1033/Refactoring
C:/Documents and Settings/tonyqus/My Documents/MSDN/Visual C# 2005 Code Snippets/application

2.  HKEY_CURRENT_USER/Software/Microsoft/VisualStudio/8.0/Languages/CodeExpansions/Visual C#/Path

这是一个REG_SZ 类型的值,可以用来存储字符串,这里用来存储路径,用分号分割,在我的机器上,它的值如下:

%InstallRoot%/VC#/Snippets/%LCID%/Visual C#/;%MyDocs%/Code Snippets/Visual C#/My Code Snippets/;%InstallRoot%/VC#/Snippets/%LCID%/OfficeDevelopment/;%InstallRoot%/VC#/Snippets/%LCID%/Refactoring/;C:/Documents and Settings/tonyqus/My Documents/code1/;C:/Program Files/Microsoft Visual Studio 8/VC#/Snippets/1033/Workflow/;C:/Documents and Settings/tonyqus/My Documents/MSDN/Visual C# 2005 Code Snippets/datatypes/

3.  C:/Documents and Settings/<Your Account Name>/Local Settings/Application Data/Microsoft/VisualStudio/8.0/1033/ExpansionsXML.xml

这是一个xml文件,结构比较复杂,我们可以看到在上面的两个设置中,仅存储目录,而在这个文件中既保存目录又保存目录中的.snippet文件的完整路径,这可能是为了提供.snippet文件的import功能而特地设计的。这里就不做展开了,大家有兴趣的话,可以研究一下它的结构。

来说说可能出现的问题:
问题 1

在HKEY_CURRENT_USER/Software/Microsoft/VisualStudio/8.0/Languages/CodeExpansions/Visual C#/Path 中存储着两个完全相同的路径,如
C:/Documents and Settings/tonyqus/My Documents/MSDN/Visual C# 2005 Code Snippets/database
C:/Documents and Settings/tonyqus/My Documents/MSDN/Visual C# 2005 Code Snippets/database/
我们可以看到这两个路径唯一的差别就是一个'/',但似乎Code Snippets Manager不会对这样的情况进行处理,它会认为这是两个完全不同的路径,所以如果出现这种情况,建议删掉其中一个。

问题 2
在注册表的两个值中目录明明存在,但却无法在智能感知时列出该目录,这可能是由于 ExpansionsXML.xml没有改目录的相关信息所致,建议删除或者重命名ExpansionsXML.xml,然后重新启动VS2005,并打开Code Snippets Manager,你会发现一个Code Snippets Manager会根据注册表中的路径新建一个新的ExpansionsXML.xml文件。

问题 3
智能感知可以列出的目录,在Code Snippets Manager的列表中根本没有,但每次试图添加目录时,会报目录已存在的错误。遇到这种情况,恐怕要对这三个存储位置都要做处理,首先要确保注册表中确实把这个目录删除了,还有就是重建ExpansionXML.xml文件。

posted @ 2006-06-29 18:23 Tony Qu 阅读(1580) | 评论 (4) | 编辑 收藏

2006年5月19日

aspnetdb.mdf数据字典

表名:aspnet_Applications
说明:保存应用程序信息

字段名  类型  属性 说明
 ApplicationName  nvarchar(256)    应用程序名
 LoweredApplicationName  nvarchar(256)    小写的应用程序名
ApplicationId  uniqueidentifier  PK 应用程序的id, GUID值
 Description  nvarchar(256)  nullable 应用程序的 描述

表名:aspnet_Paths
说明:路径信息

字段名  类型  属性 说明
 ApplicationId  uniqueidentifier  FK: appnet_Applications.ApplciationId  应用程序Id
 PathId  uniqueidentifier  PK  路径Id
 Path  nvarchar(256)    路径信息
 LoweredPath  nvarchar(256)   小写的路径信息

表名:aspnet_Users
说明:用户信息

 字段名  类型  属性  说明
 ApplicationId  uniqueidentifier    应用程序Id
 UserId  uniqueidentifier  PK 用户Id
 UserName  nvarchar(256)    用户名
 LoweredUserName  nvarchar(256)    小写的用户名
 MobileAlias  nvarchar(16)    移动电话的pin码(未使用)
 IsAnonymous  bit    是否为匿名用户
LastActivityDate  datetime    最后活动日期

表名:aspnet_Membership
说明:成员信息

 字段名  类型  属性  说明
 ApplicationId  uniqueidentifier  FK: appnet_Applications.ApplciationId  应用程序Id
 UserId  uniqueidentifier  FK: aspnet_Users.UserID 用户Id
 Password  nvarchar(128)    密码
 PasswordFormat  int   存储密码的格式 
 PasswordSalt  nvarchar(128)   密码的Hash值
 MobilePIN  nvarchar(16)    手机PIN码
 Email  nvarchar(256)    电子邮件地址
 LoweredEmail  nvarchar(256)    小写的电子邮件地址
 PasswordQuestion  nvarchar(256)    遗忘密码问题
 PasswordAnswer  nvarchar(128)    遗忘密码答案
 IsApproved  bit    
 IsLockedOut  bit    是否锁住
 CreateDate  datetime    创建时间
 LastLoginDate  datetime    最后登录时间
 LastPasswordChangedDate  datetime    最后密码更改时间
 LastLockoutDate  datetime    最后一次锁帐号的时间
 FailedPasswordAttemptCount  int    密码失败尝试次数
 FailedPasswordAttemptWindowStart  datetime    密码失败尝试窗口打开时间
 FailedPasswordAnswerAttemptCount  int    遗失密码问题尝试次数
 FailedPasswordAnswerAttemptWindowStart  datetime    遗失密码问题输入窗口打开时间
 Comment  ntext    备注

表名:aspnet_Roles
说明:角色表

 字段名  类型  属性  说明
ApplicationId  uniqueidentifier  FK: appnet_Applications.ApplciationId 应用程序Id
 RoleId  uniqueidentifier  PK  角色Id
 RoleName  nvarchar(256)    角色名称
 LoweredRoleName  nvarchar(256)    小的角色名称
 Description  nvarchar(256)  nullable  描述

表名:aspnet_UsersInRoles
说明:用户角色关系表

 字段名  类型 属性 说明
 UserID  uniqueidentifier  FK: aspnet_Users.UserId 用户ID 
 RoleID  uniqueidentifier  FK: aspnet_Roles.RoleId  角色ID

表名:aspnet_Profile
说明:Profile对象存储表

字段名 类型  属性  说明 
 UserId  uniqueidentifier  FK: aspnet_Users.UserId  用户ID
 PropertyNames  ntext    属性名称
 PropertyValuesString  ntext    字符串值
 PropertyValuesBinary  image    二进制值
LastUpdatedDate  datetime   最后更新日期 

posted @ 2006-05-19 15:28 Tony Qu 阅读(768) | 评论 (2) | 编辑 收藏

2006年5月9日

[翻译]脚本引擎实现 - 第四部分 符号表和文法树

原文地址: http://www.flipcode.com/articles/scripting_issue04.shtml
作者:Jan Niestadt
译者:Tony Qu

介绍

既然我们在上两部分中做了一些有益的事,我们就需要把我们从程序的数据结构中收集的数据保存起来,这就是我们接下来要做的事情,其中有两个相当重要的东西:符号表和文法树

符号表,有点像命名建议,它是一张包含了所有我们的程序中需要用到的符号的表,在我们的案例中,也包括所有的字符串变量和常量字符串。如果你有语言包括函数和类,那么它们也将在符号表中出现。

文法树是我们的程序结构的一种树形的表示形式,看看下面的图。在下一部分中,我们将用这个表示形式来生成中间代码,虽然并没有强制规定一定要生成文法树(因为我们已经从解析器那里获得了所有的程序结构信息),我觉得这使得编译器更加透明,这也是我写这篇文章的原因。

这将是第一个拥有“真正”代码的部分,在你看到它之前,我想澄清一点这些代码是为了更好的理解而写的,但可能结构方面不是很好,它将满足我们正在制作的编译器的需要,但真实的编译器远远不止这些。我会在遇到实际问题时,提到一些真实编译器的东西。

在规则间传递信息

很明显,我们不得不向解析器添加功能——当我们找到一个符号时,我们把它添加到符号表中,但是我们也需要“家长”规则来了解符号的描述信息(家长规则是指真正使用唯一标识符的规则)。

当我们构建一棵文法树的时候,一些相似的东西是必须的。我们需要家长规则拥有一个指向孩子规则结点的指针(孩子规则是由家长规则构建而成的)

还记得yylval集吗?Yacc也使用这个集合在规则间传递信息。在yylval集中,每个规则会有一个相关联字段,那是规则的类型。在string.y代码的最上面,你可以看到下面的类型声明

% type  < symbol >  identifier string
% type  < tnode >   statement expression

symbol和tnode是这个集合的新的结点,它们分别代表指向符号描述信息的指针和指向文法树结点的指针。

现在声明规则使用下面的类型

       |  expression END_STMT     {$$  =   new  TreeNode (EXPR_STMT, $ 1 );} 

这意味着:如果你找到一个表达式声明,构建一个新END_STMT类型的树结点(返回结点指针),这个结点有一个孩子结点,它指向这个声明的组成。$$表示规则的返回值,$1是由规则定义(表达式)中第一个符号返回的值。$2在这里没有任何意义,因为词法分析器没有为END_STMT符号设置yylval 成员。

我希望这个解释足够清楚,因为它很重要。从本质上讲,这些规则是有层次的,每个规则会返回一个值给更高层次的规则。

现在让我们看看,我们使用什么数据结构来描述符号表和文法表。

符号表
我们例子中的规则表仅有很少的信息,基本上只有变量名称和它第一次被定义的行所在的行号,当然在之后我们要用符号表来保存更多的数据。

实现其实很简单:用一个单向链表保存符号描述信息,当我们要获得一个符号的时候,可以线性搜索这个链表(看看symtab.cpp,这个文件很直观)。对于一个真实的编译器,符号表通常是用二叉搜索树或哈希表实现的,只有这样,我们才能快速获得一个符号。

当解析器找到一个符号后,我们要把符号放入符号表,需要做以下动作

 identifier
       : ID
         {
            $$  =  st.Find ($ 1 );
             if  ($$  ==  NULL)   {  //  doesn't exist yet; create it
               $$  =   new  SymDesc ($ 1 , STR_VAR, NULL, lineno);
               st.Add ($$);
            }
         }
       ;

我们把字符串常量当变量处理,这样我们可以为他们生成一个名字,并且把它放入符号表中。

要注意的是,对于更高级的编译器来说,它很有可能让词法分析器保存或获得标识符,这是因为在一个复杂的语言中有很多不同意思的标识符,比如说变量、函数、类型等。词法分析器能够获得标识符的描述信息,并且直接向解析器返回一个合适的token。由于我们的标识符总是变量,所以我就直接让解析器处理了。

文法树
对于文法树,我已经创建了一个简单的TreeNode类,该类仅保存孩子结点的指针和一些额外信息(如结点类型、一个符号的链接指针)看看吧,其实没有什么东西是难的。

正如你之前看到的,我们可以很容易地根据可识别的解析器规则构建我们的文法树:

equal_expression
       : expression EQUAL assign_expression   {$$  =  newTreeNode(EQUAL_EXPR, $ 1 , $ 3 );}
        |  assign_expression                    {$$  =  $ 1 ;}
       ;

你会发现,我们有时仅仅是从传送孩子规则传递信息给家长规则,且传送的信息保持不变;如果你的等于表达式与你的赋值表达式相同的话,就不需要特地为等于表达式产生一个额外的结点,你仅仅是使用为赋值表达式创建的结点来表示等于表达式。

这个部分(以及接下来的部分)的编译和前一个部分相同,这个程序还可以支持语法修正程序,但是现在展示的是它负责创建的符号表和语法树。

太酷了,但是……

好了,它会读取程序和分析程序了,但是它无法做一些有用的事,不是吗?
当然现在不能,我们还需要实现更多的组件,下一个部分将涵盖语法检测和中间代码生成,这将是我们向编译程序跨出的巨大一步。
我希望我的进度没有让你觉得太慢了,我其实是把注意力集中在每一个独立的组件上,而不是匆匆而过。如果你立即理解所有这些东西,那你应该感到高兴,并且可以着手试验了。

下次见
Jan Niestadt

posted @ 2006-05-09 20:15 Tony Qu 阅读(489) | 评论 (0) | 编辑 收藏

2006年4月21日

[winform入门级好书]c# Windows Forms程序设计

书名:c# Windows Forms程序设计
作者:Erik Brown[美]
译者:朱毓斌、吴飞
出版社:清华大学出版社
售价:78元
个人书评:
    本书操作步骤详细,完全可以与step by step级的书相媲美,而且涉及了许多软件工程的思想,让你能够在做软件的过程中感受软件工程的意义。全书通过制作一个相册系统,向读者传授 WinForm编程经验。适合.net初学者和.net中级开发人员。

posted @ 2006-04-21 10:06 Tony Qu 阅读(856) | 评论 (6) | 编辑 收藏

2006年4月19日

关于asp.net Session丢失问题的总结

昨天去GTSC面试,有面试官问我关于Session丢失之后怎么查的问题,说老实话,开发到现在很少碰到这样的情况,唯一想到的就是Session超时,还有就是做Session读写日志,发觉面试官听了之后不是很满意,汗!

不管怎么说,是个学习的好机会,今天抽空查了一下网上关于这些问题的处理方法,总结一下,希望对大家有所帮助。

顺便提一下asp中Session的工作原理:
asp的Session是具有进程依赖性的。ASP Session状态存于IIS的进程中,也就是inetinfo.exe这个程序。所以当inetinfo.exe进程崩溃时,这些信息也就丢失。另外,重起或者关闭IIS服务都会造成信息的丢失。

asp.net Session的实现
asp.net的Session是基于HttpModule技术做的,HttpModule可以在请求被处理之前,对请求进行状态控制,由于Session本身就是用来做状态维护的,因此用HttpModule做Session是再合适不过了。

原因1:
bin目录中的文件被改写,asp.net有一种机制,为了保证dll重新编译之后,系统正常运行,它会重新启动一次网站进程,这时就会导致Session丢失,所以如果有access数据库位于bin目录,或者有其他文件被系统改写,就会导致Session丢失

原因2:
文件夹选项中,如果没有打开“在单独的进程中打开文件夹窗口”,一旦新建一个窗口,系统可能认为是新的Session会话,而无法访问原来的Session,所以需要打开该选项,否则会导致Session丢失

原因3:
似乎大部分的Session丢失是客户端引起的,所以要从客户端下手,看看cookie有没有打开

原因4:
Session的时间设置是不是有问题,会不会因为超时造成丢失

原因5:
IE中的cookie数量限制(每个域20个cookie)可能导致session丢失

原因6:
使用web garden模式,且使用了InProc mode作为保存session的方式

解决丢失的经验
1. 判断是不是原因1造成的,可以在每次刷新页面的时候,跟踪bin中某个文件的修改时间
2. 做Session读写日志,每次读写Session都要记录下来,并且要记录SessionID、Session值、所在页面、当前函数、函数中的第几次Session操作,这样找丢失的原因会方便很多
3. 如果允许的话,建议使用state server或sql server保存session,这样不容易丢失
4. 在global.asa中加入代码记录Session的创建时间和结束时间,超时造成的Session丢失是可以在SessionEnd中记录下来的。
5. 如果有些代码中使用客户端脚本,如javascript维护Session状态,就要尝试调试脚本,是不是因为脚本错误引起Session丢失

参考:
[1] http://jinglecat.cnblogs.com/archive/2005/11/14/275587.aspx
[2] http://www.0dsf.com/bbs/dispbbs.asp?boardID=30&ID=6032&page=5
[3] http://spaces.msn.com/eparg/Blog/cns!1pnPgEC6RF6WtiSBWIHdc5qQ!447.entry
[4] http://jinlinc.cnblogs.com/archive/2005/11/29/287181.aspx
[5] http://blog.joycode.com/ghj/archive/2004/06/23/25521.aspx
[6] http://www.365base.com/Article/343/347/2005/2005091534671.html

大家如果还有其他的经验,可以写在回复中,我会即时更新的

posted @ 2006-04-19 10:33 Tony Qu 阅读(2831) | 评论 (21) | 编辑 收藏

2006年4月18日

firefox下几个实用的免费开发插件

今天在看Ajax基础教程,看到书中推荐了几个不错的工具
WebDeveloper
提供了许多开发中十分有用的环境模拟工具,如禁用JavaScript,描出页面中的隐藏表单等,对于web脚本开发人员特别有用,而且它是firefox插件
下载地址: http://chrispederick.com/work/webdeveloper/

Venkman
firefox下调试javascript的好工具,支持断点,有很详细的当前状态信息。它也是firefox插件。安装完成后,会在工具菜单中出现一个JavaScript Debugger。
下载地址: https://addons.mozilla.org/extensions/moreinfo.php?id=216

JavaScript代码模糊工具
这个工具很特别,是用Web页做的,具体怎么用,大家试试就知道了。
地址: http://hometown.aol.de/_ht_a/memtronic/MemTronic_CruncherCompressor_doc.html

posted @ 2006-04-18 10:26 Tony Qu 阅读(549) | 评论 (0) | 编辑 收藏

2006年4月16日

[翻译]脚本引擎实现 - 第三部分 解析器

原文地址: http://www.flipcode.com/articles/scripting_issue03.shtml
作者:Jan Niestadt
译者:Tony Qu

介绍

    第二部分的程序运行得很好,它把程序转换为符号(token),所有的关键字、操作符、标点符号、标识符和常数都马上被识别和记录下来。当然,你可以键入

{  this  )  =   " pointless "   +  ; 

程序会马上接受这段代码,并且生成一个符号列表,虽然以上的代码并不是我们所需要的,因为我也不知道这段代码究竟能干什么。接下来,我们必须让程序能够识别语法结构。

我们用解析器来实现这个功能,它可用来获得程序的结构并且检查语法错误。

一些语言理论
    我们怎么才能告诉解析器我们的语言是怎么样的呢?我们可以用一种叫Backus-Naur表单(BNF)的方法来指定语法,这种定义方法通过使用程序组成的基本概念来构建语法。例如,表达式可以出现在其他东西中,如标识符和字符串中。在BNF中,是这样写的:

expression: identifier  |   string ; 

声明可以是一个打印或输入声明

statement
   : PRINT expression END_STMT
   | INPUT identifier END_STMT
   ;

(记住 PRINT, INPUT和END_STMT是我们的词法分析器返回的符号)
现在,一个程序可以用一个声明列表来描述

program: | program statement; 

以上声明的意思是程序可以是空的,也可以是包含一个声明程序。这是一个很好的递归声明定义。

所以,我们在BNF中定义的语言包含以下声明:

print a;
print "Hello";
input name;

以下是非法输入

input "Hello"; 

因为我们定义了输入声明,所以input之后只能有标识符,而不是字符串常量

随着BNF的使用,我们现在可以正式定义我们整个语言的语法了,当然这还不包含文法,因此以下的声明:

a = (b == c);

它将被解析器接收,但它没有任何意义,因为我们试图把布尔值赋给一个字符串。文法将在下一步检测。

好了,现在我们知道了足够的语言规范来创建我们的解析器!

看上去很相似
    解析器也是用一个叫Yacc的外部程序生成的,Yacc是一个标准的Linux工具,就像Lex一样。我们将使用一个改进的叫作Bison的版本。Bison的用户手册可以在 这里找到。
事实上,Yacc文件(扩展名为.y)的布局和与Lex文件很像。

< definitions >
 %%
< rules >
 %%
< user_code >

文件段中包含符号(token)定义,类型信息和yylval union的定义,就像我们在前一篇文章中看到的那样,这是为什么我们使用union,Yacc使用相同的union在不同的“语言概念”,如表达式、声明和程序之间传递信息。从这些定义,Yacc会生成一个lexsymb.h文件(事实上,它会创建一个parse.cpp.h,但是parse.bat过程会把文件重命名 。)
    文件段中也会包含一些初始化代码,它们位于标志%{和}%之间,还是和Lex文件很相似,但这段不是在本部分使用的,但允许你包含任何你需要的其他代码。

rules段是根据BNF来指定的,这在上一篇文章中已有相关解释,这里就不再多提了。

在Yacc中有一个问题,那就是你的语言规范必须是LR(1)文法的,LR(1)文法的含义在“龙书”中有相关的解释(见章节4.5关于自低向上的解析),但是解析器必须能够通过查看当前解析器的符号判断语法规则来,但只允许向后查看一个符号之后。下面的规则将产生一个转换/减少冲突(shift/reduce conflict) :

 A:
    | B C
    | B C D
    | D E F
    ;

当从输入文件读到B时,继续向后查看一个C,有两个这样的组合,我们可以把它归为一组(最终,这两种替代表达式组合都会被归为A),此时该冲突不会发生。问题是第二个替代表达式以D结尾,而第三个是以D开始的,当解析器读到C时,它将无法判断是把输入归类为A2还是A1后面跟着A3,因此虽然完整的语法定义不会引起无法分析的情况,但由于解析器只能向后查看一个符号,所以会出现问题。Yacc把这种冲突叫作半模糊转换/减少冲突(shift/reduce) 或减少/减少(reduce/reduce)冲突。

好了,我不想让这些吓到你,让我们来看看规则,声明规则是最重要的:

statement
       : END_STMT                    {puts ("Empty statement");}
       | expression END_STMT         {puts ("Expression statement");}
       | PRINT expression END_STMT   {puts ("Print statement");}
       | INPUT identifier END_STMT   {puts ("Input statement");}
       | if_statement                {puts ("If statement");}
       | compound_statement          {puts ("Compound statement");}
       | error END_STMT              {puts ("Error statement");}

正如你看到的,这里定义了我们的语言中所有的声明类型,紧跟在声明后面的代码是用来告诉解析器当找到匹配的表达式时该做什么。在我看来,这种规则很直观,有一点要注意,错误声明是用来告诉Yacc当遇到一个解析错误时该怎么做(比如遇到一个非法的符号或者不匹配的符号)。在这种情况下,它会寻找下一个 END_STMT符号,并且继续解析下去。解析错误总是被报告给在main.cpp中定义的yyerror()函数,这样我们的编译器就可以用合适的方式处理错误。如果你没有在.y文件中定义一个错误规则,你的解析器会在遇到错误时停下来,这似乎并不是很好。

或许你想知道为什么会有这么多不同的表达式规则:表达式、相等表达式(equal_expression)、赋值表达式 (assign_expression)、截取表达式(concat_expression)和简单表达式,这是为了指定操作符的优先级。如果解析器看到以下声明

 if (a == b + c) 

它就应该知道这时不应该计算a==b,而是让字符串c加上一个布尔值,不同的表达式规则保证了只有唯一的方法可以解析该表达式,只要你多看它几次,它就会工作。

另一个问题解析以下表达式:

if (a == b)   if (c == d)   e = f;   else g = h; 

解析器不知道else属于哪个if声明,它可能认为你的意思是

  if (a == b)   {if (c == d)   e = f;}   else g = h; 

但在所有的语言转换中规定把else和最近的if进行组合

因为你无法通过改变规则解决这个问题,Yacc将会报告一个转换/减少冲突,Yacc通过向定义部分增加一行信息解决这个冲突

%expect 1 

意思是Yacc会期待一个冲突。Yacc是通过把else和最近的if关联起来解决这个冲突的,就像我们需要的那样。

只要你理解BNF,Yacc文件的其它部分都是可自解释,如果有任何不清楚的部分,你可以发邮件给我或者在留言板上留下你的问题。

Yacc文件可以用一下命名进行编译

bison --defines --verbose -o parse.cpp

如果你在编译过程中,发现有任何冲突,可以通过查看parse.cpp.out文件了解详细的冲突内容。(即使你没有看到任何错误,查看这个文件也是很有意义的事)如果你无法解决冲突,请把你的.y文件发给我,我会帮你看看的。
    如果一切顺利的话(就像样例代码做的那样),在parse.cpp中会有一个可用的词法分析器。我们的新程序唯一要做的就是调用yyparse()函数,整个的输入文件会被解析。
再试一次example.str,看看它是如何处理错误的。有错误吗?是的,我在第十三行漏掉了一个分号,Yeah!它工作得很好。

欢呼
    我们今天做了很多事——我们学习了正规语言理论;如何在yacc中使用这些理论;为什么Yacc对于它支持的语法如此挑剔;以及如何处理操作符。最终,我们完成了一个解析器。
    好了,最艰难的时刻已经过去,如果你理解的话,接下来的事都是小菜一碟。然而,如果你对我所说的LR(1)文法感到迷茫的话,可以留言或者发邮件给我,我会设法帮你解释清楚。当然,我也欢迎其它的问题和评论,只要我知道你们确实在读本文就行。
    未来有什么在等待着我们?下一次,我们将写两个新的组件:符号表和文法树。到那时,你有一周的时间来体验代码。提示:尝试让你的编译器接受类C的while声明。

Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1367544

理解Session State模式+FAQ [翻译]相关推荐

  1. DirectX FAQ 翻译(Graphics 部分)

    DirectX FAQ 翻译(Graphics 部分) DirectX Frequently Asked Questions Microsoft Corporation August 2005 Int ...

  2. 乱砍设计模式之二 -- STATE模式

    转自 : http://blog.csdn.net/wishfly/archive/2008/01/22/2060026.aspx STATE模式的中文名称是状态模式.在<设计模式>一书中 ...

  3. Android学习 StateMachine与State模式

    2019独角兽企业重金招聘Python工程师标准>>> 一 State模式 意图: 允许一个对象在其内部状态改变时改变它的行为.对象看起来似乎修改了它的类.(Objects for ...

  4. java state用法_Java状态模式(State模式)

    State的定义:不同的状态,不同的行为:或者说,每个状态有着相应的行为. 何时使用状态模式State模式在实际使用中比较多,适合"状态的切换".因为我们经常会使用If elsei ...

  5. <读书笔记> Thinking in python (Python 设计模式) 3. Proxy and State模式

    1.Proxy代理模式  1 #: c04:ProxyDemo.py  2   3 # Simple demonstration of the Proxy pattern.  4   5   6    ...

  6. 3.Flink-On-Yarn开发使用\原理\Session会话模式\Per-Job模式

    本文来自:Flink1.12-2021黑马程序员贺岁视频 3.Flink-On-Yarn开发使用 3.1.原理 3.2.两种模式 3.2.1.Session会话模式 3.2.2.Per-Job模式 3 ...

  7. 码率控制(一):理解码率控制模式(x264,x264,vpx)

    码率控制(一):理解码率控制模式(x264,x264,vpx) 什么是"码率控制"?它是编码器决定为每帧视频分配多少比特的工具. 视频编码(有损)的目标是尽可能多的节省比特(码率) ...

  8. State模式与Strategy模式的区别

    策略用来处理算法方式变化,而状态则是处理状态变化.     对于模式的选择反映出你对结构的想法.此刻你把它视为一种状态,如果将来你发觉用Strategy能更好的说明你的意图,你可以重构它.这两种模式在 ...

  9. Securing Session State

    ASP.NET session state授权你存储和找回用户在一个Web应用程序浏览多个页面时的用户值.ASP.NET session state 识别从同一浏览器在限制时间内的一个session和 ...

最新文章

  1. POJ 1753 Flip Game DFS枚举
  2. OpenCV小部件的姿势Pose of a widget
  3. linux之universal usb installer安装ubuntu
  4. word根据目录切块php,PHP导出Word文档如何自定义目录?
  5. [转]史上最全最强SpringMVC详细示例实战教程
  6. python describe函数_Python基础知识点梳理2,推荐收藏
  7. 创建一个jFinal项目
  8. JavaSE——Java8之函数式接口、函数式编程、Lambda表达式
  9. 3说明书_BMW新3系说明书上没写的6条信息
  10. 常用iOS URL Scheme附录 大全
  11. 坦克大战之继承的实现
  12. 中国诞生全球最强量子模拟器 量子计算迈出大步
  13. java阴历阳历_Java 阴历阳历转换
  14. excel高效之sumproduct()带权重计算 如:绩效
  15. 整理一下国内比较便宜的云主机
  16. 云南计算机专修学校附中,云南昆明这四所重点中学,师资力量雄厚,教学经验丰富!...
  17. C++ int类型转 LPCTSTR类型
  18. 解决“由于应用程序配置不正确,应用程序未能启动。重新安装应用程序可能会纠正这个问题”
  19. 用pcs,gfs2,lvm2-cluster和pacemaker 搭建FNS cluster
  20. iOS开发storyboard拖拽tableView: Static cells的使用

热门文章

  1. TCP/IP详解学习笔记 这位仁兄写得太好了
  2. 几道经典的SQL笔试题目(有答案)
  3. Unity TouchScripts实例 - 判断在物体上滑动
  4. mac 安装qemu的方法
  5. c语言一行黑白相间的瓷砖,磁砖样式——第八届蓝桥杯C语言B组(国赛)第二题...
  6. excel如何使用COUNTIF进行条件计数
  7. 用python玩转数据测试答案_MOOC_用Python玩转数据_测试答案
  8. 香港喜运佳,承载着太多的回忆
  9. 离散数学常用符号TeX输入
  10. 父进程回收子进程之wait()函数使用解读