JavaCC入门教程及相关资源

今天下午翻译了一篇简单的文章后。就去看JavaCC的东西了。。然后就找到了一篇入门教程

然后之前我是找到了一篇翻译过来的的某熊的战略储备基地

从头到尾读了一遍英文的。感觉还是英文的写的要好一些。建议对照着翻译看英文。JavaCC也就那么回事。。

同时在在这目测百慕大群岛的什么工程与应用科学学院找到了一些其他的文档。其中一篇是JavaCC-FAQ很好。基本上有关JavaCC的问题都有解释。

在FAQ里,看到了一个关于JJTree的介绍,写的不错。建议看看。

还有一个是国外某学校的编译原理课程的ppt下载,好象是以JavaCC作为工具的。还没认真看。

还有一篇JavaCC 研究与应用 ,写的平常。不过是中文版的。

最后。千万不要忘了官方文档。也包括你下载的JavaCC里面的Demo。。

Eclipse安装JavaCC

今年的编译原理课程上机实践是讲这个的。。要求用JavaCC来做一个简单的解释器。今天总算是有点时间找找文档先把这个安装了。安装过程很简单。。

  1.希望你已经安装了Eclipse。。。

  2.去sourceforge该项目主页下载javaCC压缩包

  3.下载完成后解压到你的Eclipse根目录。会提示覆盖plugins和features。直接覆盖即可。

  4.测试一下是否成功。具体步骤就是,打开eclipse,新建一个空java项目。然后对着项目点击右键new->other->javaCC->javaCC template file。然后选择命名空间。包名。和文件名就可以了。这个地方的什么的是由你建立的java项目决定的。所以你可以先把java项目设置好,然后直接选就可以了。。

  5.点击运行。选择java application。控制台输出     

Reading from standard input…  
  Enter an expression like “1+(2+3)*4;”:

  完成。。。

Update:其实吧。这里安装的是JavaCC的插件。但是已经可以进行开发了。可能你需要一个例子来开始。或者你不喜欢eclipse。那么去JavaCC的项目下载你喜欢的即可。我下的是javacc-5.0.zip 里面有例子。可以参考。

SQLServer超时时间已到解决和一套控件库

在最近的一个程序中,因为频繁的操作数据库,莫名的出现了如下的错误:

  超时时间已到。超时时间已到,但是尚未从池中获取连接。出现这种情况可能是因为所有池连接均在使用,并且达到了最大池大小。

  说明: 执行当前 Web 请求期间,出现未处理的异常。请检查堆栈跟踪信息,以了解有关该错误以及代码中导致错误的出处的详细信息。

  异常详细信息: System.InvalidOperationException: 超时时间已到。超时时间已到,但是尚未从池中获取连接。出现这种情况可能是因为所有池连接均在使用,并且达到了最大池大小。

  按理说这应该是没有关闭数据库连接或者dataset,可是查了一下。发现都关了啊。遂可以表述为原因不明,但是通过在数据库连接字符串中添加max pool size=512 这个数字可以自己设。就可以了

  这篇文章短是短了点。。好吧。那顺带分享一套非常精美的C#控件。 RadControls-For-WinForms 控件2012 RadControls-for-WPF控件2012

属性文法

我们知道,许多编译程序采用属性文法和语法制导翻译方法对语义处理工作进行比较规范和抽象的描述。

  而一个属性文法包含一个上下文无关文法和一系列文法规则,语义规则是指:对于文法的每个产生式都配备了一组属性的计算规则

  语义规则附在文法的每个产生式上,而语法制导翻译是指在语法分析过程中,完成附加在所使用的产生式上的语义规则描述的动作。

  ·语法制导:基于语法分析中用到的文法产生式

  ·翻译:完成语义分析的各项功能,不仅指生成中间代码

  形式上讲,一个属性文法是一个三元组,A=(G,V,F),其中G是一个上下文无关文法;V是有穷的属性集,每个属性与文法的一个终结符或非终结符关联,属性加工的过程即是语义处理的过程。F是关于属性的属性断言或一组属性的计算规则(称为语义规则)。断言或语义规则与一个规则式关联,只引用该规则式左端或右端的终结符或非终结符关联的属性。形式化的东西看看就好,后面给出具体例子分析。

  

既然称之为属性文法,那么什么属性呢。这些属性代表与文法符号相关信息,比如它的类型、值、代码序列、符号表内容等等。属性与变量一样,可以进行计算和传递。可以类比我们平时写代码时候一些成员变量。。属性又分为综合属性和继承属性。

  

n在一个属性文法中,对应于每个产生式A→a都有一套与之相关联的语义规则,每条规则的形式为:

  b:=f(c1,c2,…,ck),只有在已知 c1-ck 值的基础上,才能计算属性值 b, 称属性 b 依赖于属性 c1-ck,至于c1-ck依赖于哪个,就得看由c1-ck在左侧的规则了。也就是看下面的规则了。

  这里,f是一个函数,而且或者

  1. b是A的一个综合属性并且c1,c2,…,ck是产生式右边文法符号的属性,或者

  2. b是产生式右边某个文法符号的一个继承属性并且c1,c2,…,ck 是A或产生式右边任何文法符号的属性。  属性b依赖于属性c1,c2,…,ck。

  属性文法中常用记号N·t表示与非终结符号N相关联的属性t。

  

注意:¨终结符只有综合属性,由词法分析器提供

  

¨非终结符既可有综合属性也可有继承属性,文法开始符号的所有继承属性作为属性计算前的初始值

  ¨在语法树中,一个结点的综合属性的值由其子结点的属性值确定。一个结点的继承属性由此结点的父结点和/或兄弟结点的某些属性确定

  根据包含的属性类型,属性文法分为:S-属性文法和L-属性文法

  S-属性文法是仅包括综合属性的属性文法;L -属性文法是包括综合属性和继承属性的属性文法。

  给出一个简单的实例说明上面的内容:

  

考虑非终结符A,B和C,其中,A有一个继承属性a和一个综合属性b,B有综合属性c,C有继承属性d。产生式A→BC可能有规则

  C.d:=B.c+1

  A.b:=A.a+B.c

  而属性A.a和B.c在其它地方计算

  为什么是这样的,因为此时A就是A,B是X1,C是X2,对于d来说,他是产生式右部C的一个属性,c是右部B的属性,属性d依赖于属性c,和1,所以它是C的继承属性,对于c来说,他是产生式右部B的一个属性,但是c不依赖于d,而是d依赖于c所以c属性类型无法确定,对于b,他是A的一个属性,并且a是A的属性,c是产生式右部的属性,所以b是A的综合属性,而对于a,因为不能确定a属性依赖于那个属性,所以。无法得知。从上面我可以得出一个规律,对于一个属性规则来说,一条规则只能确定其左侧的属性类型,而右侧的属性需要由一个由他在左侧的规则来确定。比如,可以看到上面的规则中,c和a都不能确定,就是因为在规则右侧。

  此部分可能理解不够深刻,如有错误欢迎指正。

  参考:

  http://jpkc.hdu.edu.cn/computer/byyl/online/5-2.htm

  http://metc.gdut.edu.cn/compile/nandian/n-8.htm   

LR(1)项目集规范簇的构造

首先我们知道LR(0)的项目的形式是[A→α·β ]这样的.而在LR(1)中的项目形式是[A→α·β ,a ],其中A→α·β 为LR(0)项目,称为心,a为终结符或#,称为向前搜索符。对归约项目[A→α·,a],仅当前输入符号是a时,才能用A→α进行归约。一会将会看到具体的例子。  课本上给出的规则是:我将要对照着规则来说明,这里要强调一下,”,‘在这里是分隔符。不是终结符。他是一个标志,  以S′→·S,#属于初始项目集中,把’#‘号作为向前搜索符,表示活前缀为γ(若γ是有关S产生式的某一右部)要归约成S时,必须面临输入符为’#‘号才行。因此对初始项目S′→·S,# 求闭包后再用转换函数逐步求出整个文法的LR(1)项目集族。具体构造步骤如下:  (1) 构造LR(1)项目集的闭包函数。  a) I 的任何项目都属于CLOSURE(I) b) 若有项目[A→α·Bβ,a ]属于CLOSURE(I),B→γ是文法中的产生式,β∈V*,b∈FIRST(βa), 则[B→·γ,b]也属于CLOSURE(I)中。 c) 重复b)直到CLOSURE(I)不再增大为止。  (2) 转换函数的构造  LR(1)转换函数的构造与LR(0)的相似,GO(I,X)=CLOSURE(J) 其中I是LR(1)的项目集,X是文法符号: J={任何形如[A→αX·β,a]的项目 | [A→α·Xβ,a]∈I}  例如下列文法G′为:  (0) S′→S (1) S→aAd (2) S→bAc (3) S→aec (4) S→bed (5) A→e 构造他的LR(1)项目集规范簇。  以I0=CLOSURE(S′→·S,#)开始。运算。若有项目[A→α·Bβ,a ]属于CLOSURE(I),B→γ是文法中的产生式,β∈V*,b∈FIRST(βa), 则[B→·γ,b]也属于CLOSURE(I)中。此时,我们可以把S看成B,#看成a,然后需要求FIRST集合,此时没有β,a为#,所以FIRST(#)中只有一个b=#,而S有四个产生式。所有四个产生式加上#都是在I0中,最终求得的I0项目集为  { S′→·S,# S→·aAd,# S→·bAc,# S→·aec,# S→·bed,# }  然后使用GO函数来构造I1,从J={任何形如[A→αX·β,a]的项目 | [A→α·Xβ,a]∈I}我们可以知道I1的核(最初的产生式)就是这里的J,然后呢。X是I(也就是我们的I0)中的·后面的符号,也就是输入符。。可以看到在I0中,X可以为S,a,b,我们先以I1=GO(I0,S)=CLOSURE( S′→S·,# ),注意,·号已经前进了。因为J是I输入进一的项目,求I1,发现·后面没符号了,所以闭包就是他自己了。最终求得的I1的项目集为:  {S′→S·,# }  我们上一步是用的I1=GO(I0,S)来求得,我们求I2的时候使用GO(I0,a)来求,此时X就是a了。然后我们吧I0中符合的项目中的·后移一位得到J然后对J求闭包,就是I2了。此处J=S→a·Ad,# 和S→a·ec,# [Read More]

VS2010 编译安装boost库

实践是最好的办法。。学习C++,想试试线程,然后打算用boost库,结果boost库编译差点吓到我。。没看到比较完整的安装教程。。一直耽搁。今天动手。完成了。方法记录如下: 1.下载boost 从boost官网( http://www.boost.org )上下载最新的boost版本,现在最新是1.49版本,解压到自定义目录(我解压到了D:/program files,最终的目录结构是D:\Program Files\boost_1_49_0) 2.编译安装 在D:\Program Files\boost_1_49_0的目录下,有一个bootstrap.bat文件,直接双击运行。就会在同目录生成b2.exe;bjam.exe两个文件。 3.设定编译环境 修改user-config.jam (D:\Program Files\boost_1_49_0\tools\build\v2\user-config.jam) 的MSVC configuration MSVC configuration Configure msvc (default version, searched for in standard locations and PATH). using msvc ; 在上面这段的下面直接添加如下的文字。 using msvc : 10.0 : :/wd4819/D_CRT_SECURE_NO_DEPRECATE/D_SCL_SECURE_NO_DEPRECATE/D_SECURE_SCL=0 ; 保存关闭。 4.开始编译 点击开始->所有程序->“Microsoft Visual Studio 2010”,指向“Visual Studio tools(工具)”,然后单击“Visual Studio 2010 command prompt(命令提示)” 使用cd切换到D:\Program Files\boost_1_49_0目录。这个就不说了 然后输入如下的代码: b2 toolset=msvc-10.0 architecture=x86 instruction-set=i686 address-model=32 link=static variant=debug,release threading=multi runtime-link=shared –without-python –without-mpi –without-wave –without-graph –without-math –without-serialization stage   [Read More]

一个简单实例的LR分析过程

经过前面两篇文章。已经讲清楚了LR语法分析中最重要的分析表的构造过程。先补充一个小问题,就是LR(0)项目的分类  根据圆点所在的位置和圆点后是终结符还是非终结符或为空把项目分为以下几种:  移进项目: 形如 A→α .a β ,a是终结符, a ,b∈V* 以下同 待约项目:A→α .B β , 其中B是非终结符 归约项目:A→α . 表明产生式已分析完成。 接受项目:形如 S’→S . 特别的。A→ε的LR(0)项目只有A→ • 是归约项目  因为LR分析表的构造前面两篇文章已经讲的很清楚了,所以这个题目重要是解释一下如何使用分析表来构造,分析表的构造也许你得自己参考前面两篇文章来构造了。题目来自网络。  好,下面看题目,已知文法G[S]:  (1) S → aAcBe (2) A → b (3) A → Ab (4) B → d  写出对输入串 abbcde#的LR分析 过程。  在分析的时候,因为我们的手工分析,所以还需要一个表来记录我们的步骤。否则记不住啊。该表共需7列。行数不定。做到哪是哪。  步骤 符号栈 输入符号栈 动作 状态栈 ACTION GOTO  其中,步骤就是从1向下递增。符号栈用来保存运算中的结果,初始为#,输入符号栈保存输入串,初始值为给定的。动作里面就是用来注释是进行移进,还是规约。状态栈就是保持LR分析表的那个状态了。Action 和Goto同理  通过前两篇文章的步骤,此题可以构造出如下的一张LR分析表 [Read More]

LR(0)和SLR分析表的构造

上篇文章中,我已经说到了,LR(0)分析表是LR(0)分析器的重要组成部分,它是总控程序分析动作的依据,他是由LR(0)项目集规范族来进行构造的。他的结构主要有两个部分ACTION 和GOTO  先看看指导原则,可以直接跳过,看例题的时候可以返回来对照参考。  假设已构造出LR(0)项目集规范族为:C={I0,I1, … , In},其中Ik为项目集的名字,k为状态名,令包含S′→·S项目的集合Ik的下标k为分析器的初始状态。那么分析表的ACTION表和GOTO表构造步骤为:  ① 若项目A→α·aβ属于Ik且转换函数GO(Ik,a)= Ij,当a为终结符时则置ACTION[k,a]为Sj。 ② 若项目A→α· 属于Ik,则对任何终结符a 和’#‘号置ACTION[k,a]和ACTION[k,#]为”rj”,j为在文法G′中某产生式A→α的序号。 ③ 若GO(Ik,A)=Ij,则置GOTO[k,A]为”j”,其中A为非终结符。 ④ 若项目S′→S·属于Ik,则置ACTION[k,#]为”acc”,表示接受。 ⑤ 凡不能用上述方法填入的分析表的元素,均应填上”报错标志”。为了表的清晰我们仅用空白表示错误标志。  上篇文章的例题是这样的:LR(0)项目集规范簇也已经算出来了,共有6个I,从I0-I5,最终构造的LR(0)的分析表共7行,包括标题行,也就是ACTION和GOTO,然后是状态行,状态行和ACTION的交处分割成三列,分别是终结符号,和#终结符。也就是分割多少列取决于终结符的数目,GOTO列是非终结符,分割多少列也取决于非终结符的数目。,然后就是具体的6个状态了,画出表的结构后,如下,先不用管表的内容怎么写。    然后对照构造原则来填写表,这时你会发现要一个个从那么多的GO函数和I项目组中找对应的式子实在太难了,看不清楚,这时候,我们用GO函数把LR(0)项目集规范族连成一个识别该文法所产生的活前缀的DFA,有点像流程图了,首先把各个I项目画出来,然后需要把他们的关系表示出来,关系由GO函数确定,比如I5=GO(I2, S),则在I2和I5之间画一个箭头,由I2指向I5,线上写上S,由括号里的第二个值确定,此题构造的DFA如下图,很简单吧。    然后我们正式开始吧。第一条指导规则说到, 若项目A→α·aβ属于Ik且转换函数GO(Ik,a)= Ij,当a为终结符时则置ACTION[k,a]为Sj,我们先考察对于I0,发现S->·aS属于I0,且GO(I0,a)=I1,所有我们ACTION[0,a]置为S1.同理S->·bS属于I0,GO(I0,b)=I2,所以ACTION[0,b]置为S2。  再来看第二条规则,若项目A→α· 属于Ik,则对任何终结符a 和’#‘号置ACTION[k,a]和ACTION[k,#]为”rj”,j为在文法G′中某产生式A→α的序号,也就是说这里的j可不是I项目的标号,而是增广文法  (0)S’→S (1)S→aS (2)S→bS (3)S→a  的标号,从0-3啦。我们考察I1,发现S→·aS属于I1,且GO(I1,a)=I1,所以应该置1和a的交的格子为S1,但是此时运用第二条规则会发现S->a·也属于I1,则又应该置ACTION[1,a]为=r3,ACTION[1,#]为r3,这样就发生了冲突。这是因为大多数文法不能满足LR(0)文法的条件,对于此冲突,我们不能确定看到S->a的时候是规约还是移进,有些文法是可以直接构造的,为此,此处不能够早LR(0)分析表了,我们构造经过改进后得到了一种新的SLR(1)文法,并没有什么太大差别,主要就是解决冲突。  解决冲突的指导原则如下:  * 假设一个LR(0)项目集规范族中有如下项目集合:  {X → α.bβ,A → γ.,B → δ.}  即存在移进-归约冲突和归约-归约冲突  * 如果FOLLOW(A)∩ FOLLOW(B)∩ {b} =ф,则可以如下来解决冲突(假设当前符号是 a ): 1、若 a = b,则移进 2、若 a∈ FOLLOW(A),则用产生式 A → γ归约 3、若 a∈ FOLLOW(B),则用产生式 B → δ归约 4、否则,报错 [Read More]

LR(0)项目集规范族的构造

此文略长。我也没想到这写起来这么多,但对构造过程绝对清楚,一步步慢慢看吧。  LR的第一个L和LL的第一个L含义相同,即从左到右扫描句子 ,第二个R表示Right most最右推导。  在通常的描述中,后面还有一个括号里面的数字如,LR(0)、LR(1)这样,括号里面的数字表示用于决策所需的后续token分词数。  首先看一下LR分析器的模型图    可惜看出,LR分析器最关键的部分就是 LR分析表了,而LR分析表的构建是由已构造出的LR(0)项目集规范族来进行构造的。LR分析法貌似是不要求掌握的,而且这部分比我想象的还要复杂,今天看了好多。才勉强搞清楚这个项目集规范族的构造,但是用来锻炼思维确实不错啊。  项目集,那么字面上看就是项目的集合了,项目是什么呢。这个也确实不好说,书上是说在文法G中每个产生式的右部适当位置添加一个圆点构成LR(0)项目,举个例子吧。  比如对于  A->xyz  这条产生式可以构造的LR(0)项目就有4个  A->.xyz A->x.yz A->xy.z A->xyz.  这样很清楚了吧,就是用.分割。这个分割产生的四个项目在进行真正的语法分析的时候对应不同的操作,比如规约还是移位。这里不讨论。重点是项目集规范族的构造,  在知道了LR(0)项目后,可以来看看项目集规范族的定义,  对于构成识别一个文法活前缀的DFA项目集(状态)的全体我们称之为这个文法的LR(0)项目集规范族。至于什么是活前缀呢,定义如下  对于任一文法G[S],若S’经过任意次推导得到αAω,继续经过一次推导得到![]}/images/6b23dd171a1f672514a2dbb29175df032a1f63d4.gif)αβω,若γ是αβ的前缀,则称γ是G的一个活前缀。  现在知道了LR(0)项目,了解了活前缀,和项目集规范族的定义,还须引入LR(0)项目集的闭包函数CLOSURE和状态转换函数GO两个概念,先给出数学上的定义,如果你觉得麻烦可以跳过,后面会给出一道例题。  ① 闭包函数CLOSURE(I)的定义如下:  a)I的项目均在CLOSURE(I)中。  b)若A→α·Bβ属于CLOSURE(I),则每一形如B→·γ的项目也属于CLOSURE(I)。  c)重复b)直到不出现新的项目为止。即CLOSURE(I)不再扩大。  ② 转换函数GO(I,X)的定义:  GO(I,X)=CLOSURE(J)  其中:I为包含某一项目的状态,就是前面我们说的那四个了。,X为一文法符号,X∈(VN∪VT),J={任何形如A→αX·β的项目| A→α·Xβ属于I}。  这样就可以使用闭包函数和转换函数构造文法G′的LR(0)项目集规范族,其步骤如下:  a)置项目S′→·S为初态集的核,然后对核求闭包,CLOSURE({S′→·S})得到初态的项目集。 b)对初态集或其它所构造的项目集应用转换函数GO(I,X)=CLOSURE(J),求出新状态J的项目集。 c)重复b)直到不出现新的项目为止。  开始拿个例题来说明,定义没例题看起来看难了。  例题:对于下列文法,S→aS|bS|a,构造该文法的LR(0)项目集规范族  思路就是利用闭包函数CLOSURE和转换函数GO来构造。通过计算函数CLOSURE和GO得到文法的LR(0)项目集规范族,而GO函数则把LR(0)项目集规范族连成一个识别该文法所产生的活前缀的DFA。DFA大家都知道,有穷自动机。  (1)将文法G(S)拓广为G(S’)也就是该文法的增广文法,目的是使语法分析器知道何时应该停止并接受该串,也就是说当使用S’->S进行规约的时候,就结束。  (0)S’→S (1)S→aS (2)S→bS (3)S→a [Read More]

正规式->最小化DFA说明

今天早上去图书馆,去看编译原理,想把这部分搞清楚,看着龙书+国产的某一本不知什么的习题与解析,猜过程。。猜原理。。终于是看懂了。。 整体的步骤是三步: 一,先把正规式转换为NFA(非确定有穷自动机), 二,在把NFA通过“子集构造法”转化为DFA, 三,在把DFA通过“分割法”进行最小化。

   一步很简单,就是反复运用下图的规则,图1

  这样就能转换到NFA了。 给出一个例题,来自Google book。本文主要根据这个例题来讲,图2    二.子集构造法。 同样的例题,把转换好的NFA确定化,图3

  这个表是从NFA到DFA的时候必须要用到的。第一列第一行I的意思是从NFA的起始节点经过任意个ε所能到达的结点集合。Ia表示从该集合开始经过一个a所能到达的集合,经过一个a的意思是可以略过前后的ε。同样Ib也就是经过一个b,可以略过前后任意个ε。 至于第二行以及后面的I是怎么确定的。我参考了一些题目才明白,原来就是看上面的Ia和Ib哪个还没出现在I列,就拿下来进行运算,该列对应的Ia和Ib就是前面我说的那样推导。

  如果还不太明白,看图就是了。你会发现I中的几个项目都在Ia和Ib中出现了。而且是完全出现

  这步做完以后,为了画出最后的DFA,那么肯定得标出一些号来,比如1.2.3.。或者A。 B。c,我一般标的方法是先把I列全部标上1.2.3.递增。然后看1表示的集合和Ia和Ib中的哪个集合一样,就把那个集合也表示为1.继续向下做。最后会得到这样一个表格。图4

  至此,就可以表示出DFA了。就对照上面那个表,从0节点开始经过a到1.经过b到2,就这样画就行了。。

  最后的DFA如下图,图5

  双圈的表示终态,这个是怎么来的呢。去看看图4,会发现有些项之前有双圈标志,这个是因为在NFA图2中,9为终态,所以所有包含9的集合都被认为是终态集,改成1.2.3.。。方便画节点后就需要把这些点作为终态了。。

   三.最小化,分割法。

FA的最小化就是寻求最小状态DFA

  最小状态DFA的含义: 1.没有多余状态(死状态)2. 没有两个状态是互相等价(不可区别) 两个状态s和t等价的条件: 兼容性(一致性)条件——同是终态或同是非终态 传播性(蔓延性)条件——从s出发读入某个a和从t出发经过某个a并且经过某个b到达的状态等价。就是相同。

  DFA的最小化—例子,第一步都是固定的。分成终态和非终态

1.将M的状态分为两个子集一个由终态k1={C,D,E,F}组成,一个由非终态k2={S,A,B}组成,

2.考察{S,A,B}是否可分.

因为A经过a到达C属于k1.而S经过a到达A属于k2.B经过a到达A属于k2,所以K2继续划分为{S,B},{A},

3.考察{S,B}是否可再分:

B经过b到达D属于k1.S经过b到达B属于k2,所以S,B可以划分。划分为{S},{B}

4.考察{C,D,E,F}是否可再分: 因为C,D,E,F经过a和b到达的状态都属于{C,D,E,F}=k1所以相同,所以不可再分:

5.{C,D,E,F}以{D}来代替则,因为CDEF相同,你也可以用C来代替。无所谓的最小化的DFA如图,:

真麻烦啊。。心里清楚,还得找些图来说明。。额。。基本上感觉自己讲清楚了。。。不清楚的地方。。请留言互相讨论。。谢谢。。

参考:

http://www.worldcat.org/title/bian-yi-yuan-li-xue-xi-fu-dao/oclc/302301738

http://metc.gdut.edu.cn/compile/cmpl3/3-3.htm

编译