2017-06-19 13:47:55 +00:00
|
|
|
|
|
|
|
%{
|
|
|
|
function ERR(yy, err){
|
2017-06-19 15:31:46 +00:00
|
|
|
console.log("hmmlib error: L%d: %s\n", yy.line, err);
|
|
|
|
throw { message: err, line: yy.line };
|
2017-06-19 13:47:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function CHECKESCAPE(yy, str){
|
2017-06-19 15:31:46 +00:00
|
|
|
if("[]:@~\\\"".indexOf(str) == -1){
|
2017-06-19 13:47:55 +00:00
|
|
|
ERR(yy, "hmmlib: Unknown backslash escape code: %s", str);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function UNQUOTE(yy, str){
|
|
|
|
var i = 0;
|
|
|
|
var j = 0;
|
|
|
|
while((j = str.indexOf('\\', i)) != -1){
|
|
|
|
CHECKESCAPE(yy, str.charAt(j));
|
|
|
|
str = str.slice(i, j) + str.slice(j+1);
|
|
|
|
i = j+1;
|
|
|
|
}
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
|
|
|
function M_(yy, str, s){
|
|
|
|
yy.an.markers.push({ type: str });
|
|
|
|
yy.mnext = s;
|
|
|
|
}
|
|
|
|
|
|
|
|
function M_ADD(yy, t, n){
|
|
|
|
yy.an.markers[yy.an.markers.length - 1].marker = t.substr(0, n);
|
|
|
|
yy.an.markers[yy.an.markers.length - 1].offset = yy.an.text.length;
|
|
|
|
if(yy.mnext === "TEXT"){
|
|
|
|
yy.an.text += t.substr(0, n);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function MX_ADD(yy, c){
|
|
|
|
var m = yy.an.markers[yy.an.markers.length - 1];
|
|
|
|
if(m.parameter){
|
|
|
|
m.parameter += c;
|
|
|
|
} else {
|
|
|
|
m.parameter = c;
|
|
|
|
}
|
|
|
|
yy.an.text += c;
|
|
|
|
}
|
|
|
|
|
|
|
|
function NEWANNO(yy){
|
|
|
|
if(!yy.first) yy.annos.push(yy.an);
|
|
|
|
yy.an = {
|
|
|
|
line: yy.line,
|
|
|
|
text: "",
|
|
|
|
references: [],
|
|
|
|
markers: [],
|
|
|
|
};
|
|
|
|
yy.an.line = yy.line;
|
|
|
|
yy.first = false;
|
|
|
|
}
|
|
|
|
%}
|
|
|
|
|
|
|
|
%option reentrant
|
|
|
|
%option noyywrap
|
|
|
|
|
|
|
|
S [\t \r]*
|
|
|
|
SP [\t \r]+
|
|
|
|
ATTR_SIMPLE [^\" \]\t\r\n][^ \]\t\r\n]*
|
|
|
|
ATTR_ALNUM [0-9a-zA-Z][0-9a-zA-Z_]*
|
|
|
|
ATTR_QUOTED \"([^\n\"\\]|\\.)*\"
|
|
|
|
TAG_VIDEO_OPEN "[video"
|
|
|
|
TIMECODE \[[0-9]{1,2}(\:[0-5][0-9]){1,2}\]
|
|
|
|
BAD_TIMECODE \[[0-9]{1,2}(\:[6-9][0-9]){1,2}\]
|
|
|
|
TEXT_BREAK [^\\\:\@\~\[\]\r\n\t ]
|
|
|
|
LB \[
|
|
|
|
RB \]
|
|
|
|
|
|
|
|
%s VIDEO
|
|
|
|
%s V_ATTR
|
2017-06-20 20:15:26 +00:00
|
|
|
%s V2_ATTR
|
2017-06-19 13:47:55 +00:00
|
|
|
%s ANNOTATION
|
|
|
|
%s TEXT_START
|
|
|
|
%s TEXT
|
|
|
|
%s MARKER
|
|
|
|
%s MARKER_XTRA
|
|
|
|
%s REF
|
|
|
|
%s R_ATTR
|
|
|
|
%s AFTERTEXT
|
|
|
|
%s AUTHOR
|
|
|
|
%s CATEGORIES
|
|
|
|
%s QUOTES
|
|
|
|
|
|
|
|
%%
|
|
|
|
|
|
|
|
<<EOF>> { ERR(yy, "Unexpected EOF, video close tag not found."); }
|
|
|
|
\r\n|\n { yy.line++; }
|
|
|
|
|
|
|
|
<INITIAL>{TAG_VIDEO_OPEN} { yy_.begin("VIDEO"); }
|
|
|
|
<INITIAL>. { ERR(yy, "Missing video tag."); }
|
|
|
|
|
|
|
|
<VIDEO>{SP} {}
|
2017-06-19 17:23:17 +00:00
|
|
|
<VIDEO>member{S}\= { yy.attr = "member"; yy_.begin("V_ATTR"); }
|
|
|
|
<VIDEO>stream_platform{S}\= { yy.attr = "stream_platform"; yy_.begin("V_ATTR"); }
|
|
|
|
<VIDEO>stream_username{S}\= { yy.attr = "stream_username"; yy_.begin("V_ATTR"); }
|
|
|
|
<VIDEO>project{S}\= { yy.attr = "project"; yy_.begin("V_ATTR"); }
|
|
|
|
<VIDEO>title{S}\= { yy.attr = "title"; yy_.begin("V_ATTR"); }
|
|
|
|
<VIDEO>vod_platform{S}\= { yy.attr = "vod_platform"; yy_.begin("V_ATTR"); }
|
|
|
|
<VIDEO>id{S}\= { yy.attr = "id"; yy_.begin("V_ATTR"); }
|
2017-06-20 20:15:26 +00:00
|
|
|
<VIDEO>co\-host{S}\= { yy.attr = "co_hosts" yy_.begin("V2_ATTR"); }
|
|
|
|
<VIDEO>guest{S}\= { yy.attr = "guests" yy_.begin("V2_ATTR"); }
|
|
|
|
<VIDEO>annotator{S}\= { yy.attr = "annotators"; yy_.begin("V2_ATTR"); }
|
2017-06-19 13:47:55 +00:00
|
|
|
<VIDEO>\] { yy_.begin("ANNOTATION"); };
|
|
|
|
<VIDEO>. { ERR(yy, "Invalid char '"+ yytext +"' in video tag."); }
|
|
|
|
|
|
|
|
<V_ATTR>{SP} { yy_.begin("VIDEO"); }
|
|
|
|
<V_ATTR>{ATTR_SIMPLE} { yy.meta[yy.attr] = yytext; yy_.begin("VIDEO"); }
|
|
|
|
<V_ATTR>{ATTR_QUOTED} { yy.meta[yy.attr] = UNQUOTE(yy, yytext.substr(1, yyleng-2)); yy_.begin("VIDEO"); }
|
|
|
|
<V_ATTR>\] { yy_.less(0); yy_.begin("VIDEO"); }
|
|
|
|
|
2017-06-20 20:15:26 +00:00
|
|
|
<V2_ATTR>{SP} { yy_.begin("VIDEO"); }
|
|
|
|
<V2_ATTR>{ATTR_SIMPLE} { yy.meta[yy.attr].push(yytext); yy_.begin("VIDEO"); }
|
|
|
|
<V2_ATTR>{ATTR_QUOTED} { yy.meta[yy.attr].push(UNQUOTE(yy, yytext.substr(1, yyleng-2))); yy_.begin("VIDEO"); }
|
|
|
|
<V2_ATTR>\] { yy_.less(0); yy_.begin("VIDEO"); }
|
|
|
|
|
2017-06-19 15:31:46 +00:00
|
|
|
<ANNOTATION>\[\/video\] { NEWANNO(yy); return 1; }
|
2017-06-19 13:47:55 +00:00
|
|
|
<ANNOTATION>{TIMECODE}{LB}\@ { NEWANNO(yy); yy.an.time = yytext.substr(1, yyleng-4); yy_.begin("AUTHOR"); }
|
2017-06-19 15:31:46 +00:00
|
|
|
<ANNOTATION>{TIMECODE} { NEWANNO(yy); yy.an.time = yytext.substr(1, yyleng-2); yy_.begin("TEXT_START"); }
|
|
|
|
<ANNOTATION>{BAD_TIMECODE} { ERR(yy, "Timecode '"+ yytext +"' out of range."); }
|
|
|
|
<ANNOTATION>{SP} {}
|
|
|
|
<ANNOTATION>. { ERR(yy, "Cannot parse annotation. Expected timecode."); }
|
2017-06-19 13:47:55 +00:00
|
|
|
|
|
|
|
<TEXT_START>{LB}\: { M_(yy, "CATEGORY", "TEXT"); yy_.begin("MARKER"); }
|
|
|
|
<TEXT_START>{LB}\@ { M_(yy, "MEMBER" , "TEXT"); yy_.begin("MARKER"); }
|
|
|
|
<TEXT_START>{LB}\~ { M_(yy, "PROJECT" , "TEXT"); yy_.begin("MARKER"); }
|
2017-06-19 17:23:17 +00:00
|
|
|
<TEXT_START>{LB} { yy_.less(0); yy_.begin("TEXT"); }
|
|
|
|
<TEXT_START>. { ERR(yy, "Unknown character '"+ yytext +"' after timecode."); }
|
2017-06-19 13:47:55 +00:00
|
|
|
|
|
|
|
<TEXT>{TEXT_BREAK}+ { yy.an.text += yytext; }
|
|
|
|
<TEXT>\\. { CHECKESCAPE(yy, yytext.charAt(1)); yy.an.text += yytext.substr(1, yyleng-1); }
|
2017-06-19 17:23:17 +00:00
|
|
|
<TEXT>[ \r\t]+\: { yy.an.text += ' '; M_(yy, "CATEGORY", "TEXT"); yy_.begin("MARKER"); }
|
|
|
|
<TEXT>[ \r\t]+\@ { yy.an.text += ' '; M_(yy, "MEMBER" , "TEXT"); yy_.begin("MARKER"); }
|
|
|
|
<TEXT>[ \r\t]+\~ { yy.an.text += ' '; M_(yy, "PROJECT" , "TEXT"); yy_.begin("MARKER"); }
|
|
|
|
<TEXT>{LB}\: { M_(yy, "CATEGORY", "MARKER_XTRA"); yy_.begin("MARKER"); }
|
|
|
|
<TEXT>{LB}\@ { M_(yy, "MEMBER" , "MARKER_XTRA"); yy_.begin("MARKER"); }
|
|
|
|
<TEXT>{LB}\~ { M_(yy, "PROJECT" , "MARKER_XTRA"); yy_.begin("MARKER"); }
|
2017-06-19 13:47:55 +00:00
|
|
|
<TEXT>\] { yy_.begin("AFTERTEXT"); }
|
|
|
|
<TEXT>{LB}ref { yy.ref.offset = yy.an.text.length; yy_.begin("REF"); }
|
|
|
|
<TEXT>{LB} {}
|
|
|
|
<TEXT>{SP} { yy.an.text += ' '; }
|
|
|
|
<TEXT>. { yy.an.text += yytext; }
|
|
|
|
|
|
|
|
<MARKER>{ATTR_ALNUM} { M_ADD(yy, yytext); yy_.begin(yy.mnext); };
|
|
|
|
<MARKER>{ATTR_QUOTED} { M_ADD(yy, yytext.substr(1, yyleng-2)); yy_.begin(yy.mnext); };
|
|
|
|
<MARKER>. { ERR(yy, "Cannot parse Marker. Expected quoted or alphanumeric attribute."); }
|
|
|
|
|
2017-06-19 17:23:17 +00:00
|
|
|
<MARKER_XTRA>\\] { MX_ADD(yy, ']'); }
|
|
|
|
<MARKER_XTRA>\\\# { MX_ADD(yy, '#'); }
|
|
|
|
<MARKER_XTRA>\] { yy_.begin("TEXT"); }
|
|
|
|
<MARKER_XTRA>[ ] { if(yy.an.markers[yy.an.markers.length - 1].parameter){ MX_ADD(yy, ' '); } }
|
|
|
|
<MARKER_XTRA>[ ]\#[0-9]+ {
|
|
|
|
var m = yy.an.markers[yy.an.markers.length - 1];
|
|
|
|
if(m.type == "PROJECT"){
|
|
|
|
m.episode = yytext.substr(2);
|
|
|
|
} else {
|
|
|
|
MX_ADD(yytext.substr(1));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
<MARKER_XTRA>. { MX_ADD(yy, yytext); }
|
2017-06-19 13:47:55 +00:00
|
|
|
|
|
|
|
<REF>{SP} {}
|
|
|
|
<REF>site{S}\= { yy.attr = "site"; yy_.begin("R_ATTR"); }
|
|
|
|
<REF>page{S}\= { yy.attr = "page"; yy_.begin("R_ATTR"); }
|
|
|
|
<REF>url{S}\= { yy.attr = "url"; yy_.begin("R_ATTR"); }
|
|
|
|
<REF>title{S}\= { yy.attr = "title"; yy_.begin("R_ATTR"); }
|
|
|
|
<REF>article{S}\= { yy.attr = "article"; yy_.begin("R_ATTR"); }
|
|
|
|
<REF>author{S}\= { yy.attr = "author"; yy_.begin("R_ATTR"); }
|
|
|
|
<REF>editor{S}\= { yy.attr = "editor"; yy_.begin("R_ATTR"); }
|
|
|
|
<REF>publisher{S}\= { yy.attr = "publisher"; yy_.begin("R_ATTR"); }
|
|
|
|
<REF>isbn{S}\= { yy.attr = "isbn"; yy_.begin("R_ATTR"); }
|
|
|
|
<REF>\] { yy.an.references.push(yy.ref); yy.ref = {}; yy_.begin("TEXT"); }
|
|
|
|
<REF>. { ERR(yy, "Unexpected item in ref: " + yytext); }
|
|
|
|
|
|
|
|
<R_ATTR>{SP} {}
|
|
|
|
<R_ATTR>{ATTR_SIMPLE} { yy.ref[yy.attr] = yytext; yy_.begin("REF"); }
|
|
|
|
<R_ATTR>{ATTR_QUOTED} { yy.ref[yy.attr] = UNQUOTE(yy, yytext.substr(1, yyleng-2)); yy_.begin("REF"); }
|
|
|
|
|
2017-06-19 15:31:46 +00:00
|
|
|
<AFTERTEXT>\[\/video\] { NEWANNO(yy); return 1; }
|
2017-06-19 13:47:55 +00:00
|
|
|
|
|
|
|
<AFTERTEXT>{SP} {}
|
|
|
|
<AFTERTEXT>{LB}quote { yy_.begin("QUOTES"); }
|
|
|
|
<AFTERTEXT>{LB}\: { yy_.begin("CATEGORIES"); yy_.less(1); }
|
|
|
|
<AFTERTEXT>{LB}[0-9] { yy_.begin("ANNOTATION"); yy_.less(0); }
|
|
|
|
<AFTERTEXT>.. { ERR(yy, "Unexpected thing after text node: " + yytext); }
|
|
|
|
<AFTERTEXT>. { ERR(yy, "Unexpected thing after text node: " + yytext); }
|
|
|
|
|
|
|
|
<AUTHOR>[^\]\n]+\] { yy.an.author = yytext.substr(0, yyleng-1); yy_.begin("TEXT_START"); }
|
|
|
|
<AUTHOR>{SP} {}
|
|
|
|
|
|
|
|
<CATEGORIES>{SP} {}
|
|
|
|
<CATEGORIES>\:{ATTR_SIMPLE} { yy.an.markers.push({ type: "CATEGORY", marker: yytext.substr(1, yyleng-1), offset: -1 }); }
|
|
|
|
<CATEGORIES>\:{ATTR_QUOTED} { yy.an.markers.push({ type: "CATEGORY", marker: UNQUOTE(yy, yytext.substr(2, yyleng-3)), offset: -1 }); }
|
|
|
|
<CATEGORIES>\]{LB} { yy_.begin("QUOTES"); }
|
|
|
|
<CATEGORIES>\] { yy_.begin("ANNOTATION"); }
|
|
|
|
<CATEGORIES>. { ERR(yy, "Unexpected character in category tag: " + yytext); }
|
|
|
|
|
|
|
|
<QUOTES>{SP} {}
|
2017-06-20 20:15:26 +00:00
|
|
|
<QUOTES>[0-9]+{S}\] { yy.an.quote = { author: "", id: parseInt(yytext) }; yy_.begin("ANNOTATION"); }
|
2017-06-19 13:47:55 +00:00
|
|
|
<QUOTES>{ATTR_ALNUM} { yy.an.quote.author += yytext; }
|
|
|
|
<QUOTES>. { ERR(yy, "Unexpected character in quotes tag: " + yytext); }
|
|
|
|
|
|
|
|
%%
|