GF徽标

使用蟒蛇 哈斯克尔 Java语言 C类#绑定到C运行时

Krasimir Angelov,2015年7月至2017年8月

选择语言:哈斯克尔 蟒蛇 Java语言 C类#

加载语法

在使用之前蟒蛇导入所需的绑定PGF2模块pgf模块pgf包PGFSharp包:
>>>导入pgf
前奏曲>导入PGF2
导入org.grammaticalframework.pgf.*;
使用PGFSharp;
导入模块后,可以使用目录帮助函数查看可用的功能类型。目录获取对象并返回可用方法的列表在对象中:
>>>目录(pgf)
帮助稍微高级一点,它会尝试为了生成更易于阅读的文档包含注释:
>>>帮助(pgf)
通过调用加载语法方法pgf.readPGF函数readPGF方法PGF.readPGF方法PGF.ReadPGF:
>>>gr=pgf.readPGF(“App12.pgf”)
序曲PGF2>gr<-readPGF“App12.pgf”
PGF gr=PGF.readPGF(“App12.PGF”);
PGF gr=PGF.ReadPGF(“App12.PGF”);
您可以从语法中查询可用语言集。可通过酒店进入语言哪一个是从语言名称到对象的映射pgf.浓度类型Concr公司Concr公司Concr公司代表语言。例如,以下内容将提取英语:
>>>eng=gr.languages[“AppEng”]>>>打印(eng)<pgf.Concr对象位于0x7f7dfa4471d0>
序曲PGF2>let Just eng=Data.Map.lookup“AppEng”(语言gr)前奏曲PGF2>:t engeng::混凝土
Concr eng=gr.getLanguages().get(“AppEng”);
Concr eng=gr.Languages[“AppEng”];

正在分析

所有特定于语言的服务都可以作为类的方法pgf.浓度将类型的对象作为参数的函数Concr公司类的方法Concr公司类的方法Concr公司.例如,要调用解析器,可以调用:
>>>i=eng.parse(“这是一个小剧院”)
前奏曲PGF2>let res=parse eng(startCat gr)“这是一个小剧场”
Iterable<ExprProb>Iterable=eng.parse(gr.getStartCat(),“这是一个小剧场”);
IEnumerable<Tuple<Expr,float>>enumerable=eng.Parse(“这是一个小剧场”);
这为您提供了一个迭代器,可以枚举所有可能的抽象树。你可以打电话找到下一棵树下一个:
>>>p,e=i.next()
如果您使用的是Python 3,则可以调用__next__:
>>>p,e=i.__next__()
这将为您提供类型的结果分析输出.如果结果是分析失败那么解析器失败了,您将获取偏移量和解析器被卡住的标记。如果解析成功那么你会得到分析确定具有潜在的无限解析结果列表:
前奏曲PGF2>让ParseOk((e,p):rest)=res
这为您提供了一个可枚举所有可能的抽象树。你可以打电话找到下一棵树下一个:
迭代器<ExprProb>iter=iterable.Iterator();ExprProb ep=iter.next();
这为您提供了一个可枚举的,可以枚举所有可能的抽象树。你可以打电话找到下一棵树移到下一行:
IEnumerator=可枚举。GetEnumerator();枚举器.MoveNext();元组<Expr,float>ep=枚举器.Current;

结果是概率和树的对。概率是负对数概率,这意味着number编码最可能的结果。可能的树是以递减的概率顺序返回(即增加负对数)。第一棵树应该最小第页:

>>>打印(p)35.9166526794
序曲PGF2>打印p35.9166526794
System.out.println(ep.getProb());35.9166526794
Console.WriteLine(ep.Item2);35.9166526794
这是相应的抽象树:
>>>打印(e)PhrUtt NoPConj(UttS(UseCl(TTAnt TPres ASimul)PPos(PredVP(DetNP(Det Quant this_Quant NumSg)))(UseComp(CompNP(德勤指数艺术品编号)(AdjCN(PositA small_A)(Use N剧院编号))))NoVoc
序曲PGF2>打印PhrUtt NoPConj(UttS(UseCl(TTAnt TPres ASimul)PPos(PredVP(DetNP(Det Quant this_Quant NumSg)))(UseComp(CompNP(德勤指数艺术品编号)(AdjCN(PositA small_A)(Use N剧院编号))))NoVoc
System.out.println(ep.getExpr());PhrUtt NoPConj(UttS(UseCl(TTAnt TPres ASimul)PPos(PredVP(DetNP(Det Quant this_Quant NumSg)))(UseComp(CompNP(德勤指数艺术品编号)(AdjCN(PositA small_A)(Use N剧院编号))))NoVoc
Console.WriteLine(ep.Item1);PhrUtt NoPConj(UttS(UseCl(TTAnt TPres ASimul)PPos(PredVP(DetNP(Det Quant this_Quant NumSg)))(UseComp(CompNP(德勤指数艺术品编号)(AdjCN(PositA small_A)(Use N剧院编号))))NoVoc

注意,根据语法,对于一句话你可能会得到无数棵树。在其他情况下,树的数量可能是有限的,但仍然是巨大的。解析器是专门设计为惰性的,这意味着每棵树一找到就在耗尽之前归还完整的搜索空间。对于模式数为的语法树木最好只采摘顶部N个忽略其余的。

这个解析方法还具有以下可选参数:
开始类别
n个最大树数
启发式从0到1的实数
回调类别和回调函数列表

例如,通过使用这些参数,可以更改解析器或限制从解析器返回的树的数量。例如可以按如下方式使用不同的开始类别进行解析:

>>>i=eng.parse(“一个小剧场”,cat=pgf.readType(“NP”))
还有一个功能使用启发式分析哪一个再取两个参数,这样可以更好地控制针对解析器的行为:
Prelude PGF2>let res=parseWithHeuristics eng(startCat gr)heuristic_factor回调
还有一种方法使用启发式分析哪一个再取两个参数,这样可以更好地控制针对解析器的行为:
Iterable<ExprProb>Iterable=eng.parseWithHeuristics(gr.startCat(),heuristic_factor,回调);
这个分析方法还具有以下可选参数:
开始类别
启发式从0到1的实数

例如,通过使用这些参数,可以更改解析器。例如,可以按以下方式使用不同的开始类别进行解析:

IEnumerable<Tuple<Expr,float>>enumerable=eng.Parse(“这是一个小剧场”,cat:Type.ReadType(“NP”));

启发式因素可用于以解析速度换取质量。默认情况下,树列表按概率排序,这与系数0.0。当我们增加因子时,解析变得更快但与此同时,排序变得不精确。最糟糕的系数为1.0。无论如何,解析器总是返回相同的但顺序不同。我们的经验是,这甚至是一个因素约为0.6-0.8,翻译语法仍按顺序排列最有可能的树在列表顶部,但在列表的下面,树木变得乱糟糟的。

回调是可用于识别的函数列表文字。例如,我们使用它们来识别姓名和未知信息翻译中的单词。

线性化

您可以将解析器的结果线性化为另一个解析器语言,或者可以显式构造树,然后用任何语言将其线性化。例如,我们可以创建这样的新表达式:
>>>e=pgf.readExpr(“AdjCN(PositA red_A)(UseN剧院_N)”)
序曲PGF2>let Just e=readExpr“AdjCN(PositA red_A)(UseN剧院_N)”
Expr e=Expr.readExpr(“AdjCN(PositA red_A)(UseN剧院_N)”);
Expr e=Expr.ReadExpr(“AdjCN(PositA red_A)(UseN剧院_N)”);
然后我们可以将其线性化:
>>>打印(英语线性化(e))红色剧场
前奏曲PGF2>putStrLn(线性化工程)红色剧场
System.out.println(eng.linearize(e));红色剧场
Console.WriteLine(eng.Linearize(e));红色剧场
这种方法只产生一次线性化。如果使用变体在语法中,你可能想看到所有可能的线性化。为了这个目的,你应该使用线性化所有:
>>>对于英语中的s,线性化所有(e):打印红色剧场红色剧场
前奏曲PGF2>mapM_ putStrLn(linearizeAll eng e)红色剧场红色剧场
for(字符串s:eng.linearizeAll(e)){System.out.println(s);}红色剧场红色剧场
foreach(eng.LinearizeAll(e)中的字符串s){控制台.WriteLine;}红色剧场红色剧场
相反,如果您需要一个包含所有可能形式的变形表那么正确的方法是表格线性化:
>>>eng.tabular线性化(e):{的Sg Nom':'红色剧院','的Pl Nom’:'红色剧场','s Pl Gen':“红色剧场”,'s Sg Gen':‘红色剧场’}
序曲PGF2>表格线性化工程[(“Sg Nom”,“红色剧场”),(“s Sg Gen”,“红剧场的”)
for(Map.Entry<String,String>Entry:eng.tabularLinearize(e).entrySet()){System.out.println(entry.getKey()+“:”+entry.getValue());}s Sg Nom:红色剧院s Pl Nom:红色剧院s Pl Gen:红色剧院s Sg Gen:红色剧院
foreach(eng.TabularLinearize(e).EntrySet()中的Map.Entry<String,String>Entry){////TODOConsole.WriteLine(entry.Key+“:”+entry.Value);}s Sg Nom:红色剧院s Pl Nom:红色剧院s Pl Gen:红色剧院s Sg Gen:红色剧院

最后,您还可以得到一个线性化,它被括在短语列表:

>>>[b]=eng.bracketd线性化(e)>>>打印(b)(CN:4(AP:1(A:0红色))(CN:3(N:2剧院))
前奏曲PGF2>let[b]=括号线性化工程前奏曲PGF2>putStrLn(showBracketedString b)(CN:4(AP:1(A:0红色))(CN:3(N:2剧院))
对象[]bs=eng.bracketdLinearize(e);
括号b=eng.BracketedLinearize(e);
上面序列中的每个元素都是字符串或对象类型为pgf.支架.当它实际上是一个括号时,那么对象具有以下属性:
  • -这个括号的句法范畴
  • 外国直接投资-在带括号的字符串中标识此括号的id。如果存在不连续短语,则属于同一短语的所有括号将共享此id。
  • 林指数-构成指数
  • 乐趣-这个括号的抽象函数
  • 儿童-包含此括号子项的列表
上面的列表包含类型为的元素带括号字符串.此类型有两个构造函数:
  • 叶子只有一个类型的参数字符串包含当前单词的
  • 支架具有以下参数:
    • cat::字符串-这个括号的句法范畴
    • fid::整数-在带括号的字符串中标识此括号的id。如果存在不连续短语,则属于同一短语的所有括号将共享此id。
    • 林德克斯::Int-构成指数
    • fun::字符串-这个括号的抽象函数
    • children::[BracketedString]-包含此括号子项的列表
上面序列中的每个元素都是字符串或对象类型为支架.当它实际上是一个括号时,那么对象具有以下公共最终变量:
  • 字符串cat-这个括号的句法范畴
  • 整数fid-在带括号的字符串中标识此括号的id。如果存在不连续短语,则属于同一短语的所有括号将共享此id。
  • int林德克斯-构成指数
  • 弦乐-这个括号的抽象函数
  • 对象[]子对象-包含此括号子项的列表
上面序列中的每个元素都是字符串或对象类型为支架.当它实际上是一个括号时,那么对象具有以下公共最终变量:
  • 字符串cat-这个括号的句法范畴
  • 整数fid-在带括号的字符串中标识此括号的id。如果存在不连续短语,则属于同一短语的所有括号将共享此id。
  • int林德克斯-构成指数
  • 弦乐-这个括号的抽象函数
  • 对象[]子对象-包含此括号子项的列表

即使树中有函数,线性化也有效它没有线性化定义。在这种情况下,你只会在生成的字符串中看到函数的名称。有时可以查看函数是否是否线性化。可以这样做:
>>>打印(eng.hasLinearization(“apple_N”))真的
序曲PGF2>打印(hasLinearization eng“apple_N”)真的
System.out.println(eng.hasLinearization(“apple_N”));真的
Console.WriteLine(eng.HasLinearization(“apple_N”));////TODO公司真的

分析和构造表达式

可以分析和转换已构建的树在宿主应用程序中。例如,您可以解构将树转换为函数名和参数列表:

>>>e.拆包()('AdjCN',[<pgf.Expr对象位于0x7f7df6db78c8>,<pgf.Expr对象位于x7f7DF6db7878>])
前奏曲PGF2>unApp eJust(“AdjCN”,[…,…])
ExprApplication应用程序=e.unApp();System.out.println(app.getFunction());for(Expr参数:app.getArguments()){System.out.println(arg);}
ExprApplication应用程序=e.UnApp();System.out.println(app.Function);foreach(app.Arguments中的Expr arg){Console.WriteLine(arg);}

根据的形式,解压缩的结果可能不同树。如果树是一个函数应用程序,那么您总是会得到函数名的元组和参数列表。如果相反树只是一个文本字符串,则返回值为实际值字面意义的。例如,结果来自:

>>>pgf.readExpr(“literal”).unpack()“文字”
结果来自unApp(运行应用程序)只是如果表达式是一个应用程序,并且没有什么在所有其他情况下。类似地,如果树是文本字符串,则返回值unStr(无Str)只是使用实际文字。例如,结果来自:
序曲PGF2>readExpr“\”literal\“”>>=unStr“文字”
结果来自unApp(运行应用程序)不是无效的如果表达式是一个应用程序,并且无效的在所有其他情况下。类似地,如果树是文本字符串,则返回值unStr(无Str)不会的无效的使用实际文字。例如,输出来自:
Expr elit=Expr.readExpr(“\”literal\“”);System.out.println(elit.unStr());
结果来自取消应用程序不是无效的如果表达式是一个应用程序,并且无效的在所有其他情况下。类似地,如果树是文本字符串,则返回值取消Str不会的无效的使用实际文字。例如,输出来自:
Expr elit=Expr.ReadExpr(“\”literal\“”);Console.WriteLine(elit.UnStr());
只是字符串“literal”。可以检测到这种情况在Python中,通过检查打开.也可以获得整数或浮点数用于GF中其他可能的文字类型。 还有一些功能无抗体,unInt(取消Int),取消浮动unMeta(未元数据)对于所有其他可能的情况。 还有一些方法无抗体,unInt(取消Int),取消浮动unMeta(未元数据)对于所有其他可能的情况。 还有一些方法联合抗体,取消Int,取消浮动UnMeta(未元数据)对于所有其他可能的情况。

建造新树也很容易。您可以使用读Expr从字符串中读取树,或者您可以从现有的部分构建新树。这可以通过以下方式实现使用构造函数pgf.支出:
>>>quant=pgf.readExpr(“DetQuant索引艺术编号”)>>>e2=pgf.Expr(“DetCN”,[quant,e])>>>打印(e2)DetCN(DetQuant IndefArt NumSg)(AdjCN(PositA red_A)(UseN剧院_N))
使用函数mk应用程序,mkStr公司,mkInt公司,mk浮点mk元:
序曲PGF2>let Just quant=readExpr“DetQuant IndefArt NumSg”序曲PGF2>让e2=mkApp“DetCN”[quant,e]序曲PGF2>打印e2DetCN(DetQuant IndefArt NumSg)(AdjCN(PositA red_A)(UseN剧院_N))
使用构造函数Expr公司:
Expr数量=Expr.readExpr(“DetQuant IndefArt NumSg”);Expr e2=新Expr(“DetCN”,新Expr[]{quant,e});System.out.println(e2);
使用构造函数Expr公司:
Expr数量=Expr.ReadExpr(“DetQuant IndefArt NumSg”);Expr e2=新Expr(“DetCN”,新Expr[]{quant,e});控制台.WriteLine(e2);

嵌入式GF语法

如果宿主应用程序需要执行大量表达式操作,那么使用更高级的API对语法很有帮助,在GF中也称为“嵌入式语法”。优点是您可以以更紧凑的方式构造和分析表达式。

在Python中,您首先必须嵌入语法调用:

>>>gr.embed(“应用程序”)<模块“应用程序”(内置)>
之后,无论何时需要API,都应导入模块:
>>>导入应用程序

现在创建新树只需调用普通Python功能:

>>>打印(App.DetCN(数量,e))DetCN(DetQuant IndefArt NumSg)(AdjCN(PositA red_A)(UseN house_N))

为了访问API,您首先需要生成一个带有编译器的样板Haskell模块:

$gf-制造-输出格式=haskell App.pgf
此模块将以抽象语法公开所有函数作为数据类型构造函数与转换方法Haskell数据的通用表达式,反之亦然。当您需要API时,只需导入模块即可:
序曲PGF2>导入应用程序

现在创建新树只需要编写普通的Haskell代码:

序曲PGF2应用程序>打印(gf(GDetCN(GDeQuant GIndefArt GNumSg)(GAdjCN(GPositA Gred_A)(GUseN Ghouse_N)))
唯一的区别是每个抽象语法函数的名称编译器添加了一个大写字母“G”,以确保没有冲突并且所有名称都是Haskell数据构造函数的有效名称。在这里玻璃纤维是一个函数它将数据类型表示转换为通用GF表达式。

逆向函数前景将表达式转换为数据类型表达式。例如,如果您想进行模式匹配,这很有用关于表达式的结构:

就诊=病例fg e2,共例GDetCN数量cn->do putStrLn“Found DetCN”访问cnGAdjCN adj cn->do putStrLn“找到AdjCN”访问cne->返回()

为了访问API,您首先需要生成一个带有编译器的样板Java类:

$gf-make-输出格式=java App.pgf
此类将以抽象语法公开所有函数作为方法。现在创建新树只是编写普通Java的问题代码:
System.out.println(App.DetCN(quant,cn));
如果语法名太长,无法写在每个函数前面name,然后可以使用较短的名称创建实例:
应用程序a=新应用程序();System.out.println(a.DetCN(数量,cn));

在C#中,您首先必须嵌入语法调用:

动态g=gr.嵌入()

现在创建新树只需调用普通C#方法:

控制台.WriteLine(g.DetCN(数量,e))DetCN(DetQuant IndefArt NumSg)(AdjCN(PositA red_A)(UseN house_N))

通过使用访问者模式,分析表达式也变得更加容易。在面向对象语言中,这是一种笨拙的方法在大多数函数式语言中称为模式匹配。您需要定义一个类,每个函数都有一个方法在您要处理的抽象语法中。如果调用函数(f)然后需要一个名为打开_f.方法每次遇到相应的函数时都会调用,它的参数将是来自原始树的参数。如果没有匹配的方法名,则运行库将调用该方法违约以下是一个示例:

>>>课堂示例访问者:定义on_DetCN(self、quant、cn):打印(“Found DetCN”)中国访问(自我)定义on_AdjCN(self,adj,cn):打印(“找到AdjCN”)中国访问(自我)def默认值(self,e):通过>>>e2.visit(ExampleVisitor())找到DetCN找到AdjCN
这里我们调用该方法参观从树e2开始,我们给出它作为参数,是类的实例示例访问者.示例访问者有两种方法on_DetCN上on_AdjCN当top函数当前树是DetCN公司AdjCN公司相应地。在这个例子中,我们只打印一条消息,然后我们打电话给参观递归地深入到树中。

通过使用访问者模式,分析表达式也变得更加容易。在面向对象语言中,这是一种笨拙的方法在大多数函数式语言中称为模式匹配。您需要定义一个类,每个函数都有一个方法在您要处理的抽象语法中。如果调用函数(f)然后需要一个名为打开_f.方法每次遇到相应的函数时都会调用,它的参数将是来自原始树的参数。如果没有匹配的方法名,则运行库将调用该方法默认案例以下是一个示例:

e2.visit(new Object()){DetCN上的公共void(Expr-quant,Expr-cn){System.out.println(“找到DetCN”);中国访问(this);}AdjCN上的公共无效(Expr adj,Expr cn){System.out.println(“发现AdjCN”);中国访问(this);}公共无效defaultCase(Expr e){System.out.println(“found”+e);}});找到DetCN找到AdjCN
这里我们调用该方法参观从树e2开始,我们给出它作为参数,是具有两个方法的类的实例on_DetCN上on_AdjCN当top函数当前树是DetCN公司AdjCN公司相应地。在这个例子中,我们只打印一条消息,然后我们打电话给参观递归地深入到树中。

访问形态学词典

有两种方法可以让您直接访问形态词汇。第一种方法可以转储完整形式的词典。下面的代码只是遍历词典并打印每个词典词形及其可能的分析:
>>>对于eng.fullFormLexicon()中的条目:>>>打印(条目)
序曲PGF2>mapM_print[(form,lemma,analysis,prob)|(form、analysis)<-fullFormLexicon eng,(lemma、anaAnalysis、prob)<-analysis]
for(FullFormEntry条目:eng.fullFormLexicon()){for(形态分析分析:entry.getAnalyses()){System.out.println(entry.getForm()+“”+分析.getProb()+;}}
foreach(eng.FullFormLexicon中的FullFormEntry条目){////TODOforeach(条目分析中的形态分析){Console.WriteLine(条目.Form+“”+分析.Prob+“”+analysis.Lemma+“”>分析.Field);}}
第二个实现了一个简单的查找。这个论点是一个词形式和结果是分析列表:
>>>打印(eng.lookupMorpho(“字母”))[('letter_1_N','s Sg Nom',inf),('letter _2_N','s Sg Nam',inf)]
序曲PGF2>打印(查找变形字母“letter”)[('letter_1_N','s Sg Nom',inf),('letter _2_N','s Sg Nam',inf)]
for(MorphoAnalysis an:eng.lookupMorpho(“letter”)){System.out.println(an.getLemma()+“,”+an.getField()=“,”+an.getProb());}letter_1_N,s序列号,inf字母_2_N,s序列号,inf
foreach(MorphoAnalysis and in eng.LookupMorpho(“字母”)){////TODOConsole.WriteLine(an.Lemma+“,”+an.Field+“,“+an.Prob);}letter_1_N,s序列号,inf字母_2_N,s序列号,inf

访问抽象语法

有一个简单的API用于访问抽象语法。例如,您可以获得抽象函数列表:
>>>gr.功能....
序曲PGF2>功能gr....
列表<String>funs=gr.getFunctions()....
IEnumerable<String>funs=gr.函数;....
或类别列表:
>>>gr.类别....
前奏曲PGF2>类别gr....
列表<String>cats=gr.getCategories();....
IEnumerable<String>cats=类别;....
您还可以访问具有相同结果类别的所有函数:
>>>gr.functionsByCat(“工作日”)[“周五”、“周一”、“周六”、“周日”、“周四”、“周二”、“周三”]
序曲PGF2>functionsByCat gr“Weekday”[“周五”、“周一”、“周六”、“周日”、“周四”、“周二”、“周三”]
List<String>funsByCat=gr.getFunctionsByCat(“Weekday”);....
IEnumerable<String>funsByCat=gr.FunctionsByCat(“Weekday”);....
函数的完整类型可以检索为:
>>>打印(gr.functionType(“DetCN”))检测->中国->NP
序曲PGF2>打印(functionType gr“DetCN”)公正(Det->CN->NP)
System.out.println(gr.getFunctionType(“DetCN”));检测->中国->NP
Console.WriteLine(gr.FunctionType(“DetCN”));检测->中国->NP

类型检查抽象树

运行时类型检查器可以进行类型检查和类型推断对于简单类型。依赖类型仍未完全实现在当前运行时中。推理是用方法完成的推断表达式:

>>>e,ty=gr.inferExpr(e)>>>打印(e)AdjCN(PositA red_A)(使用剧院_N)>>>打印(Y)中国
前奏曲PGF2>let Right(e',ty)=inferExpr gr e前奏曲PGF2>打印e’AdjCN(PositA red_A)(使用剧院_N)序曲PGF2>打印中国
类型表达式te=gr.inferExpr(e);System.out.println(te.getExpr()+“:”+te.getType());AdjCN(PositA red_A)(UseN剧院_N):CN
TypedExpr te=gr.InferExpr(e);////TODO公司Console.WriteLine(te.Expr+“:”+te.Type);AdjCN(PositA red_A)(UseN剧院_N):CN
结果是可能更新的表达式及其类型。在这个在这种情况下,我们总是处理简单的类型,这意味着新的表达式将始终等于原始表达式。然而,这在添加依赖类型时不会为true。

类型检查也很简单:

>>>e=gr.checkExpr(e,pgf.readType(“CN”))>>>打印(e)AdjCN(PositA red_A)(使用剧院_N)
序曲PGF2>让Just ty=readType“CN”序曲PGF2>让右侧e’=检查Expr gr e ty前奏曲PGF2>打印e’AdjCN(PositA red_A)(使用剧院_N)
Expr new_e=gr.checkExpr(e,Type.readType(“CN”));System.out.println(e)
Expr new_e=gr.CheckExpr(e,Type.ReadType(“CN”));////TODO公司控制台.WriteLine(e)

如果出现类型错误,您将得到一个错误:

>>>e=gr.checkExpr(e,pgf.readType(“A”))pgf.TypeError:表达式AdjCN(PositA red_A)(UseN剧院_N)的预期类型为A,但推断出CN
序曲PGF2>让Just ty=readType“A”前奏曲PGF2>let Left msg=checkExpr gr e ty前奏曲PGF2>putStrLn消息
Expr e=gr.checkExpr(e,Type.readType(“A”))TypeError:表达式AdjCN(PositA red_A)(UseN剧院_N)的预期类型为A,但推断出了CN

部分语法加载

默认情况下,整个语法被编译为单个文件由抽象语法组成的语法将全部具体化语言。对于具有多种语言的大型语法,这可能是因为加载变慢,语法需要更多内存。为此,你可以把语法分成一个文件用于抽象语法,而一个文件则用于每个具体语法。这是通过使用选项完成的-分裂型pgf在编译器中:

$gf-制造-拆分-pgf App12.pgf

现在您可以像往常一样加载语法,但这次只加载将加载抽象语法。您仍然可以使用语言属性获取语言列表和相应的具体语法对象:
>>>gr=pgf.readPGF(“App.pgf”)>>>eng=gr.languages[“AppEng”]
然而,如果您现在尝试使用具体的语法,那么您将获取异常:
>>>eng.lookupMorpho(“字母”)回溯(最近一次调用):文件““,第1行,inpgf.pgf错误:未加载具体语法
在使用具体语法之前,需要显式加载它:
>>>发动机负荷(“AppEng.pgf_c”)>>>打印(eng.lookupMorpho(“字母”))[('letter_1_N','s Sg Nom',inf),('letter _2_N','s Sg Nam',inf)]
当你不再需要这种语言时,你可以简单地卸载它:
>>>发动机卸载()

部分语法加载

默认情况下,整个语法被编译为单个文件由抽象语法组成的语法将全部具体化语言。对于具有多种语言的大型语法,这可能是因为加载变慢,语法需要更多内存。为此,你可以把语法分成一个文件用于抽象语法,而一个文件则用于每个具体语法。这是通过使用选项完成的-分裂型pgf在编译器中:

$gf-制造-拆分-pgf App12.pgf
这将创建以下文件:
正在编写App.pgf。。。正在写入AppEng.pgf_c。。。正在写入AppSwe.pgf_c。。。...

现在可以加载语法了批准.pgf像往常一样,但这次只有将加载抽象语法。您仍然可以使用语言属性获取语言列表和相应的具体语法对象:
PGF gr=PGF.readPGF(“App.PGF”)Concr eng=gr.getLanguages().get(“AppEng”)
然而,如果您现在尝试使用具体的语法,那么您将获取异常:
eng.lookupMorpho(“字母”)回溯(最近一次调用):文件““,第1行,inpgf.pgf错误:未加载具体语法
在使用具体语法之前,需要显式加载它:
发动机负荷(“AppEng.pgf_c”)for(MorphoAnalysis an:eng.lookupMorpho(“letter”)){System.out.println(an.getLemma()+“,”+an.getField()=“,”+an.getProb());}letter_1_N,s序列号,inf字母_2_N,s序列号,inf
当你不再需要这种语言时,你可以简单地卸载它:
发动机卸载()

图形Viz

GraphViz用于可视化抽象语法树和解析树。在这两种情况下,结果都是GraphViz代码,可以用于渲染树。请参见以下示例:

>>>打印(gr.graphviz抽象树(e))图表{n0[label=“AdjCN”,style=“solid”,shape=“plaintext”]n1[label=“PositA”,style=“solid”,shape=“明文”]n2[label=“red_A”,style=“solid”,shape=“plaintext”]n1--n2[style=“solid”]n0--n1[style=“solid”]n3[label=“UseN”,style=“solid”,shape=“plaintext”]n4[label=“theare_N”,style=“solid”,shape=“plaintext”]n3--n4[style=“solid”]n0--n3[style=“solid”]}
序曲PGF2>putStrLn(graphvizAbstractTree gr graphvizzDefaults e)图表{n0[label=“AdjCN”,style=“solid”,shape=“plaintext”]n1[label=“PositA”,style=“solid”,shape=“明文”]n2[label=“red_A”,style=“solid”,shape=“plaintext”]n1--n2[style=“solid”]n0--n1[style=“solid”]n3[label=“UseN”,style=“solid”,shape=“plaintext”]n4[label=“theare_N”,style=“solid”,shape=“plaintext”]n3--n4[style=“solid”]n0--n3[style=“solid”]}
System.out.println(gr.graphvizAbstractTree(e));图表{n0[label=“AdjCN”,style=“solid”,shape=“plaintext”]n1[label=“PositA”,style=“solid”,shape=“明文”]n2[label=“red_A”,style=“solid”,shape=“plaintext”]n1--n2[style=“solid”]n0--n1[style=“solid”]n3[label=“UseN”,style=“solid”,shape=“plaintext”]n4[label=“theare_N”,style=“solid”,shape=“plaintext”]n3--n4[style=“solid”]n0--n3[style=“solid”]}
Console.WriteLine(gr.GraphvizAbstractTree(e));////TODO公司图表{n0[label=“AdjCN”,style=“solid”,shape=“plaintext”]n1[label=“PositA”,style=“solid”,shape=“明文”]n2[label=“red_A”,style=“solid”,shape=“plaintext”]n1--n2[style=“solid”]n0--n1[style=“solid”]n3[label=“UseN”,style=“solid”,shape=“plaintext”]n4[label=“theare_N”,style=“solid”,shape=“plaintext”]n3--n4[style=“solid”]n0--n3[style=“solid”]}
>>>打印(eng.graphvizParseTree(e))图表{节点[形状=明文]子图{rank=相同;n4[标签=“CN”]}子图{rank=相同;边[style=invis]n1[标签=“AP”]n3[标签=“CN”]n1——n3}n4--n1n4--n3子图{rank=相同;边[style=invis]n0[标签=“A”]n2[标签=“N”]n0--n2}n1--n0n3——n2子图{rank=相同;边[style=invis]n100000[label=“red”]n100001[label=“剧院”]n100000--n100001}n0---n100000n2——n100001}
序曲PGF2>putStrLn(graphvizParseTree eng graphvizzDefaults e)图表{节点[形状=明文]子图{rank=相同;n4[标签=“CN”]}子图{rank=相同;边[style=invis]n1[标签=“AP”]n3[标签=“CN”]n1——n3}n4--n1n4--n3子图{rank=相同;边[style=invis]n0[标签=“A”]n2[标签=“N”]n0--n2}n1--n0n3——n2子图{rank=相同;边[style=invis]n100000[label=“red”]n100001[label=“剧院”]n100000--n100001}n0---n100000n2——n100001}
System.out.println(eng.graphvizParseTree(e));图表{节点[形状=明文]子图{rank=相同;n4[标签=“CN”]}子图{rank=相同;边[style=invis]n1[标签=“AP”]n3[标签=“CN”]n1——n3}n4--n1n4--n3子图{rank=相同;边[style=invis]n0[标签=“A”]n2[标签=“N”]n0--n2}n1--n0n3——n2子图{rank=相同;边[style=invis]n100000[label=“red”]n100001[label=“剧院”]n100000--n100001}n0---n100000n2——n100001}
Console.WriteLine(eng.GraphvizParseTree(e));////TODO公司图表{节点[形状=明文]子图{rank=相同;n4[标签=“CN”]}子图{rank=相同;边[style=invis]n1[标签=“AP”]n3[标签=“CN”]n1——n3}n4--n1n4--n3子图{rank=相同;边[style=invis]n0[标签=“A”]n2[标签=“N”]n0--n2}n1--n0n3——n2子图{rank=相同;边[style=invis]n100000[label=“red”]n100001[label=“剧院”]n100000--n100001}n0---n100000n2——n100001}