尽管在文档和论坛中搜索了很长时间,但我仍然无法在node.js 中使用JSON格式为Jison启动条件找到正确的语法
> ** Documentation at http://zaach.github.io/jison/docs/ says:
> // Using the JSON format, start conditions are defined with an array
> // before the rule’s
> matcher {rules:[
> [['expect'], '[0-9]+"."[0-9]+', 'console.log( "found a float, = " + yytext );'
> ]]}
但不幸的是,没有人不提供完整的工作样本。
我试图排除两个标签之间的任何文本。在lex中,将使用启动条件。Jison的文件说它应该有效。尽管如此,由于Jison的错误消息不是很直观,我希望能找到一个工作样本来继续前进。
有人会有解决方案吗?
var jison = require("jison").Parser;
grammar = {
"lex": {
"rules" : [ [" +" , "/* skip whitespace */"]
,[['mode1'], '[0-z]+\b' , "return 'INFO';"]
,[['mode1'], '<\/extensions>' , "this.popState(); return 'EXTEND';"]
,['<extensions>' , "this.begin('mode1'); return 'EXTSTART';"]
,['$' , "return 'EOL';"]
]
}, // end Lex rules
"bnf": { // WARNING: only one space in between TOKEN ex: "STOP EOF"
'data': [["EOL" , "this.cmd='EMPTY' ; return (this);"]
,['EXTSTART INFO EXTEND EOL' ,"this.cmd='EXTEN';this.value=$2;return (this);"]
]
}};
parser = new jison(grammar);
test= "
<extensions>
<opencpn:start></opencpn:start><opencpn:end></opencpn:end>
<opencpn:viz>1</opencpn:viz>
<opencpn:guid>714d1d6e-78be-46a0-af6e-2f3d0c505f6d</opencpn:guid>
</extensions>";
data=parser.parse (test);
我当前的样本失败
/node_modules/jison/nod_module/jison lex/regexp lexer.js:42startConditions〔conditions〔k〕〕.rules.push(i);
不幸的是,没有人回答我的问题:)
为了找到正确的语法,我不得不对Jison-Lexer代码进行逆向工程。我想这可能会帮助其他人,答案如下:)
Jison的词法条件在JSON语法下运行良好,但它们应该在名为"startConditions"的数组中预先声明,如下例所示。
grammar = {
"lex": {
"startConditions" : { "INITIAL":"// Default initial Jison/Lex context"
,"MOD_EXT": "// extenstions context "
,"MOD_RTE": "// routes context"
},
"rules" : [['[\n\s]+' , "/* skip whitespace & new lines */"]
// extensions blocs
,[['INITIAL'], '<extensions>' , "this.begin('MOD_EXT');"]
,[['MOD_EXT'], '<\/extensions>' , "this.popState();"]
,[['MOD_EXT'], '[<>\/\-\s\n]', "/* ignore */"]
,[['MOD_EXT'], '[0-z]+' , "/* ignore */"]
Etc...
为了让每个人的生活更轻松,下面是一个简单的工作示例
// Sample JISON start conditions with Jason syntax
var jison = require("jison").Parser;
grammar = {
"lex": {
"macros": { // few usefull macro
"slash": "\/",
"space": "\s+",
"quot" : "\'",
"dquot": "\"",
"dot" : "\.",
"digit": "[0-9]",
"int" : "-?([0-9]+)",
"float": "-?([0-9]*\.[0-9]+)",
"hexa" : "([0-9]|(a-h)|(A-H])+"
},
"startConditions" : { "INITIAL":"// Default initial Jison/Lex context"
,"MOD_EXT": "// extenstions context "
,"MOD_RTE": "// routes context"
},
"rules" : [['[\n\s]+' , "/* skip whitespace & new lines */"]
// extensions blocs
,[['INITIAL'], '<extensions>' , "this.begin('MOD_EXT');"]
,[['MOD_EXT'], '<\/extensions>' , "this.popState();"]
,[['MOD_EXT'], '[<>\/\-\s\n]', "/* ignore */"]
,[['MOD_EXT'], '[0-z]+' , "/* ignore */"]
// routes points blocs
,[['INITIAL'],'<rtept' , "this.begin('MOD_RTE'); return 'RTE_BEG';"]
,[['MOD_RTE'], '<\/rtept>' , "this.popState(); return 'RTE_END';"]
,[['MOD_RTE'], 'lat=' , "return 'LAT';"]
,[['MOD_RTE'], 'lon=' , "return 'LON';"]
,[['MOD_RTE'], '{float}' , "return 'CARD';"]
,[['MOD_RTE'], '<name>' , "return 'NAME_BEG';"]
,[['MOD_RTE'], '<\/name>' , "return 'NAME_END';"]
,[['MOD_RTE'], '<time>' , "return 'TIME_BEG';"]
,[['MOD_RTE'], '<\/time>' , "return 'TIME_END';"]
,[['MOD_RTE'], '<sym>' , "return 'SYM_BEG';"]
,[['MOD_RTE'], '<\/sym>' , "return 'SYM_END';"]
,[['MOD_RTE'], '<type>' , "return 'TYPE_BEG';"]
,[['MOD_RTE'], '<\/type>' , "return 'TYPE_END';"]
,[['MOD_RTE'], '<extensions>' , "this.begin('MOD_EXT');"]
,[['MOD_RTE'], '([0-z]|[-+])+\b' , "return 'TEXT';"]
,[['MOD_RTE'], '[>{quot}{dquot}{space}]' , "// ignore"]
// end of parsing buffer
,['$' , "return 'EOL';"]
]
}, // end Lex rules
"bnf": { // WARNING: only one space in between TOKEN ex: "STOP EOF"
'data': [
["EOL" , "return ('EMPTY');"]
,["ROUTEPOINTS EOL", "return (this.route);"]
]
// handle multiple waypoints
// A routepoint should at least have a LAT+LONG+NAME
,'ROUTEPOINTS' : [ // store all waypoint in an array
["ROUTEPOINT", "console.log('Parsing First Waypts=%j',this.waypts);this.route=[]; this.route.push(this.waypts);"]
,["ROUTEPOINTS ROUTEPOINT", "console.log('Parsing Next Waypts=%j',this.waypts);;this.route.push(this.waypts);"]
]
// A routepoint should at least have a LAT+LONG+NAME
,'ROUTEPOINT' : [ // <rtept lat='47.542780648' lon='-2.896743643'>...
["RTE_BEG LATITUDE LONGITUDE DATE NAME SYM TYPE RTE_END", "this.waypts={lat:$2,lon:$3,name:$5,date:$4};"]
,["RTE_BEG LATITUDE LONGITUDE DATE NAME RTE_END", "this.waypts={lat:$2,lon:$3,name:$5,date:$4};"]
,["RTE_BEG LATITUDE LONGITUDE NAME RTE_END", "this.waypts={lat:$2,lon:$3,name:$4,date:'unknow'};"]
]
// lat='47.542780648'
,'LATITUDE' : [["LAT CARD", "$$=$2;"]]
// lon='-2.896743643'
, 'LONGITUDE' : [["LON CARD", "$$=$2;"]]
//<time>2014-09-16T21:55:19Z</time>
, 'DATE' : [["TIME_BEG TEXT TIME_END", "$$=$2;"]]
// <name>001</name>
, 'NAME' : [["NAME_BEG TEXT NAME_END", "$$=$2;"]]
// <sym>001</name>
, 'SYM' : [["SYM_BEG TEXT SYM_END", "//ignore"]]
// <name>001</name>
, 'TYPE' : [["TYPE_BEG TEXT TYPE_END", "//ignore"]]
}};
parser = new jison(grammar);
test= "
<extensions>
<opencpn:start></opencpn:start><opencpn:end></opencpn:end>
<opencpn:viz>1</opencpn:viz>
<opencpn:guid>714d1d6e-78be-46a0-af6e-2f3d0c505f6d</opencpn:guid>
</extensions>
<rtept lat='47.542780648' lon='-2.896743643'>
<time>2014-09-16T21:55:19Z</time>
<name>001</name>
<sym>diamond</sym>
<type>WPT</type>
<extensions>
<opencpn:guid>408c309c-6a8c-411d-815b-0c0054646d45</opencpn:guid>
<opencpn:viz>1</opencpn:viz>
<opencpn:viz_name>0</opencpn:viz_name>
<opencpn:auto_name>1</opencpn:auto_name>
</extensions>
</rtept>
<rtept lat='44.542780648' lon='-4.896743643'>
<time>2014-08-16T21:55:19Z</time>
<name>002</name>
</rtept>
<rtept lat='43.542780648' lon='-5.896743643'>
<name>003</name>
</rtept>
<rtept lat='48.542780648' lon='-3.896743643'>
<time>2014-10-16T21:55:19Z</time>
<name>004</name>
<sym>diamond</sym>
<type>WPT</type>
<extensions>
<opencpn:guid>408c309c-6a8c-411d-815b-0c0054646d45</opencpn:guid>
<opencpn:viz>1</opencpn:viz>
<opencpn:viz_name>0</opencpn:viz_name>
<opencpn:auto_name>1</opencpn:auto_name>
</extensions>
</rtept>";
route=parser.parse (test);
console.log ("nnMy GPX route's waypoints");
for (var waypts in route) {
console.log (" -- name: %s Lon: %s Lat:%s Date:%s", route [waypts].name, route [waypts].lat, route [waypts].lon, route [waypts].date);
};
console.log ("done");