// A parser for Semantics of Business Vocabulary and Rules (SBVR), an OMG standard. // Converts from Structured English (SBVR-SE) to Logical Formulation (SBVR-LF) // Specification: http://www.omg.org/spec/SBVR/1.0/ // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . ometa SBVRParser { isTerm :x = ?SBVRParser._isTerm(x), isVerb :x = ?SBVRParser._isVerb(x), isKwrd :x = ?SBVRParser._isKwrd(x), isFctp :x = ?SBVRParser._isFctp(x), isKwrdSt :p :q = &(spaces seq(q) word:w) {q!=''?q+' '+w:w}:w {p+' '+w}:n (isKwrd(n) -> true | isKwrdSt(p, w) -> true), isTermSt :p :q = &(spaces seq(q) word:w) {q!=''?q+' '+w:w}:w {p+' '+w}:n (isTerm(n) -> true | isTermSt(p, w) -> true), isVerbSt :p :q = &(spaces seq(q) word:w) {q!=''?q+' '+w:w}:w {p+' '+w}:n (isVerb(n) -> true | isVerbSt(p, w) -> true), findVar :x = {this.ruleVars[x[1]]}, bind :x = findVar(x):y -> [`bind, x, y], spaces = seq(' ')*, letters = letter+:l -> l.join(''), num = spaces digit+:n -> [`num, parseInt(n.join(''))], word = spaces letters:w ~isVerb(w) ~isTerm(w) ~isKwrd(w) -> w, nrText = (word:w ~isKwrdSt(w,'')~isTermSt(w,'')~isVerbSt(w,'')->w)+:w -> w.join(' '), kwrd :x = spaces letters:w {x!=''?x+' '+w:w}:w (isKwrd(w) -> w | kwrd(w):a -> a), token :x = kwrd(''):t ?(t==x) -> [`kwrd, t], termR :x = spaces letters:w {x!=''?x+' '+w:w}:w (isTerm(w) -> w | termR(w):a -> a), term = termR(''):t {this._termForm(t)}:t -> [`term, t], mkVerb :x = {this.verbs[x] = true} -> [`verb, x], verbR :x = spaces letters:w {x!=''?x+' '+w:w}:w (isVerb(w) -> w | verbR(w):a -> a), verb = verbR(''):v {this._verbForm(v)}:v -> [`verb, v], quant = "each" &term -> [`univQ] | ("a"|"an"|"some") &term -> [`existQ] | "at" "most" ("one"->[`num, 1]|num):n &term -> [`atMostQ, [`maxCard, n]] | "at" "least" ("one"->[`num, 1]|num):n &term -> [`atLeastQ, [`minCard, n]] | "more" "than" ("one"->[`num, 2]|num:n {++n[1]}->n):n &term -> [`atLeastQ, [`minCard, n]] | "exactly" ("one"->[`num, 1]|num):n &term -> [`exactQ, [`card, n]] | "at" "least" ("one"->[`num, 1]|num):n "and" "at" "most" ("one"->[`num, 1]|num):m &term -> [`numRngQ, [`minCard, n], [`maxCard, m]], adVar :x ={this.ruleVars[x[1]] = this.ruleVarsCount++} ("that" "the" terbRi([[]], x):q -> [`var, [`num, this.ruleVars[x[1]]], x, q] |"that" qTerbRi([[]], x):q -> [`var, [`num, this.ruleVars[x[1]]], x, q] | -> [`var, [`num, this.ruleVars[x[1]]], x]), atfo :c = isFctp(c[0]) {c[0] = [`fcTp].concat(c[0])} -> {d = [`aFrm]; d.concat(c)}, terbRi :c :i = term:t verb:v bind(t):b {c[0]=c[0].concat([t,v]);c.concat([b])}:c (qTerbRi(c,i)), qTerbRi :c :i =(quant:q term:t adVar(t):a verb:v bind(t):b {q=q.concat([a]);c[0]=c[0].concat([t,v]);c.concat([b])}:c (qTerbRi(c,i)):r -> q.concat([r]) | verb:v bind(i):b {c[0]=c[0].concat([i,v]);c.concat([b])}:c (atfo(c)|qTerm(c)|qTerbR(c)) | bind(i):b {c[0]=c[0].concat([i]);c.concat([b])}:c atfo(c) ), qTerm :c = quant:q term:t adVar(t):a bind(t):b {q=q.concat([a]);c[0]=c[0].concat([t]);c.concat([b])}:c atfo(c):r -> q.concat([r]), qTerbR :c = quant:q term:t adVar(t):a verb:v bind(t):b {q=q.concat([a]);c[0]=c[0].concat([t,v]);c.concat([b])}:c (atfo(c)|qTerm(c)|qTerbR(c)):r -> q.concat([r]), modRule = spaces (``It is obligatory that'' qTerbR([[]]):q -> [`obl, q] | ``It is necessary that'' qTerbR([[]]):q -> [`nec, q] | ``It is prohibited that'' qTerbR([[]]):q -> [`obl, ['neg', q]] | ``It is impossible that'' qTerbR([[]]):q -> [`nec, ['neg', q]] | ``It is not possible that'' qTerbR([[]]):q -> [`nec, ['neg', q]] | ``It is possible that'' qTerbR([[]]):q -> [`pos, q] | ``It is permissible that'' qTerbR([[]]):q -> [`prm, q]), newRule = ``R:'' &((~'\n' char)*):a {this.ruleVarsCount=1} modRule:r -> [`rule, r, [`text, a.join('')]], terb = term:t (verb|nrText:f mkVerb(f)):v -> [t, v], fcTp = ``F:'' {t=[]} (terb:b {t.concat(b)}:t)+ (term:e {t.concat([e])}:t)? {this.fctps[t] = true} -> [`fcTp].concat(t), newTerm = ``T:'' nrText:t {this.terms[t] = true;} -> [`term, t], line = newTerm | fcTp | newRule, linef = line:l ('\n'|seq('\n\r')|end) -> l | '\n' -> '', expr = linef*:l -> [`model].concat(l) } SBVRParser.kwrds = {} SBVRParser.terms = {} SBVRParser.verbs = {} SBVRParser.fctps = {} SBVRParser.ruleVars = {} SBVRParser.ruleVarsCount = 0 kwrds = ["a", "an", "each", "at", "most", "least", "exactly", "that", "the", "one", "more", "than", "and"] for (var idx = 0; idx < kwrds.length; idx++){SBVRParser.kwrds[kwrds[idx]] = true} SBVRParser._isKwrd = function(k) { return this.kwrds.hasOwnProperty(k) } SBVRParser._isTerm = function(k) { if(this.terms.hasOwnProperty(k)){ return true } else if(k.slice(-1)=='s' && this.terms.hasOwnProperty(k.slice(0,-1))){return true} else return false } SBVRParser._termForm = function(k) { if(k.slice(-1)=='s' && this.terms.hasOwnProperty(k.slice(0,-1))){ return k.slice(0,-1) } else return k } SBVRParser._isVerb = function(k) { if(this.verbs.hasOwnProperty(k)) {return true} } SBVRParser._isVerb = function(k) { if(this.verbs.hasOwnProperty(k)) { return true } else if( k.slice(0,3)=='are' && this.verbs.hasOwnProperty('is' + k.slice(3)) ) { return true } else if(k=='have' && this.verbs.hasOwnProperty('has')) { return true } else return false } SBVRParser._verbForm = function(k) { if(k.slice(0,3)=='are' && this.verbs.hasOwnProperty('is' + k.slice(3))){ return 'is' + k.slice(3) } else if(k=='have' && this.verbs.hasOwnProperty('has')) { return 'has'} else return k } SBVRParser._isFctp = function(k) { return this.fctps.hasOwnProperty(k) } model1 = 'T: pilot T: plane F: pilot can fly plane F: pilot is experienced R: It is obligatory that each pilot can fly at least 1 plane R: It is obligatory that each pilot that is experienced can fly at least 3 planes' model2 = 'T: student F: student is school president R: It is obligatory that a student is school president T: module F: student is registered for module R: It is obligatory that each student is registered for at most 5 modules T: study programme F: student is enrolled in study programme F: module is available for study programme R: It is obligatory that each student that is registered for a module is enrolled in a study programme that the module is available for T: lecturer F: student is under probation R: It is obligatory that each student is registered for at most 5 modules R: It is obligatory that each student that is under probation is registered for at most 3 modules R: It is obligatory that at most 10 students are under probation F: lecturer grades student for study programme with grade R: It is prohibited that a student that is under probation is enrolled in more than 2 study programmes R: It is obligatory that each student is registered for each module' model3 = 'T: student T: module T: study programme F: student is registered for module F: student is enrolled in study programme F: module is available for study programme R: It is obligatory that each student is registered for at most 5 modules R: It is obligatory that each student that is registered for a module is enrolled in a study programme that the module is available for F: student is under probation R: It is obligatory that each student that is under probation is registered for at most 3 modules' modelT = 'T: resource T: transaction T: lock F: lock is exclusive F: lock is shared F: resource is under lock F: lock belongs to transaction R: It is obligatory that each resource is under at most 1 lock that is exclusive' tree = SBVRParser.matchAll(model2, 'expr') eval(translateCode(readFile('PrettyTree'))) Prettify.match(tree,'elem')