Advertisement
Guest User

Untitled

a guest
Nov 18th, 2019
88
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 12.63 KB | None | 0 0
  1.  
  2. // стартовый символ
  3. textStart = '<программа>'
  4. // терминал переменной
  5. textVar = '<ид.>'
  6. // терминал числа
  7. textNumber = '<цел.>'
  8. // правила
  9. textRules = `
  10.  
  11. <программа> ::= <совок.опер.>
  12. <совок.опер.> ::= <оператор> <совок.опер.> |
  13.  
  14. <оператор> ::= <опер.присв.> | <усл.опер.> | <опер.цикла>
  15.  
  16. <опер.присв.> ::= <ид.> = <ар.выр.> ;
  17.  
  18. <усл.опер.> ::= ЕСЛИ ( <лог.выр.> ) <совок.опер.> ИНАЧЕ <совок.опер.> КОНЕЦ_ЕСЛИ
  19.  
  20. <опер.цикла> ::= ЦИКЛ_ПОКА ( <лог.выр.> ) <совок.опер.> КОНЕЦ_ЦИКЛ
  21.  
  22. <ар.выр.> ::= <E>
  23. <E> ::= <T> <E-список>
  24. <E-список> ::= + <T> <E-список> |
  25. <T> ::= <F> <T-список> |
  26. <T-список> ::= * <F> <T-список> |
  27. <F> ::= <ид.> | <цел.>
  28.  
  29. <лог.выр.> ::= <F> <лог.опер.> <F>
  30. <лог.опер.> ::= > | <
  31.  
  32. `
  33. // код
  34. textCode = `
  35. d=2*3+1;
  36. a=3+2*d;
  37. c=2*d+3*a;
  38. ЕСЛИ (d>c)
  39. a=d*2;
  40. ИНАЧЕ
  41. a=d;
  42. КОНЕЦ_ЕСЛИ
  43. i=1;
  44. ЦИКЛ_ПОКА(i<10)
  45. i=i+1;
  46. КОНЕЦ_ЦИКЛ
  47. `
  48.  
  49. // textRules = `
  50. // <start> ::= <program>
  51.  
  52. // <program> ::= <op_list>
  53. // <op_list> ::= <op> <op_list>
  54. // <op_list> ::=
  55.  
  56. // <op> ::= <id> := <E> ;
  57. // <op> ::= <if>
  58. // <op> ::= <for>
  59.  
  60. // <if> ::= ЕСЛИ ( <expression> ) ТО <op> <else>
  61. // <else> ::= ИНАЧЕ <op>
  62. // <else> ::=
  63.  
  64. // <for> ::= for ( <id> := <F> , <F> <increment> ) <op>
  65. // <increment> ::= , <F>
  66. // <increment> ::=
  67.  
  68. // // <E> ::= <T> [ - <T> ]*
  69. // <E> ::= <T> <E-list>
  70. // <E-list> ::= - <T> <E-list>
  71. // <E-list> ::=
  72.  
  73. // <T> ::= <F> <T-list>
  74. // <T-list> ::= % <F> <T-list>
  75. // <T-list> ::=
  76.  
  77. // <F> ::= <id>
  78. // <F> ::= <C>
  79.  
  80. // <expression> ::= <F> <logic> <F>
  81. // <logic> ::= >
  82. // <logic> ::= <
  83. // `
  84. // textNumber = '<C>'
  85. // textVar = '<id>'
  86.  
  87. // textCode = `
  88. // d := 32 - 1 ;
  89. // a := 3 - 254 % d ;
  90. // c := 200 % d - 367 % a ;
  91. // ЕСЛИ ( d > c ) ТО a := d % 2 ; ИНАЧЕ a := d % 3 ;
  92. // h := 10 ;
  93. // for ( i := 1 , d , 2 ) h := h - 1 ;
  94. // `
  95.  
  96.  
  97. log = console.log
  98. Array.prototype.unique = function(){
  99. return Array.from(new Set(this))
  100. }
  101.  
  102. // массив правил: [ {"index":0,"from":"<start>","to":["<program>"]}, ...]
  103. rules = textRules.split('\n')//
  104. .filter(e=>e && !e.startsWith('//'))//
  105. .map(e=>e.split('::='))//
  106. .flatMap(([k,v])=>v.split('|').map(e=>[k, e]))//
  107. .map(([k,v],i)=>({
  108. index: i,
  109. from: k.trim(),
  110. to: v.split(/\s+/).filter(Boolean)//
  111. }))
  112.  
  113. log(rules)
  114. s = rules.map(e=>e.from).unique()
  115. a = rules.flatMap(e=>e.to).unique().filter(e=>!s.includes(e))
  116.  
  117. //
  118. // ["for", "(", ",", ")", "<number>", "if", "then", "else", ";", "<variable>", ":=", ">", "-", "%",
  119. // "<start>", "<program>", "<for>", "<increment>", "<if>", "<else>", "<block>", "<statement>",
  120. // "<expression>", "<compare>", "<compare2>", "<minus>", "<minus2>", "<div>", "<div2>"]
  121. types = a.concat(s).unique()
  122. //
  123. words = a.filter(e=>!e.match(/<.*>/))
  124.  
  125.  
  126.  
  127.  
  128. lexer = {
  129. string: textCode,
  130. index: 0,
  131. finished: false,
  132.  
  133. words: words,
  134. terms: types,
  135.  
  136. get char() {
  137. return this.string[this.index]
  138. },
  139. get nextChar() {
  140. return this.string[this.index + 1]
  141. },
  142. startIndex: 0,
  143. get slice() {
  144. return this.string.slice(this.startIndex, this.index)
  145. },
  146.  
  147. move() {
  148. this.index++
  149. return this
  150. },
  151.  
  152. isDigit(c) {
  153. return '0' <= c && c <= '9'
  154. },
  155. isLetter(c) {
  156. return 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z'
  157. || 'А' <= c && c <= 'Я' || c == '_'
  158. },
  159. isWhitespace(c) {
  160. return ' \n\t\r'.includes(c)
  161. },
  162.  
  163. Lexeme: function(type, value='') {
  164. this.type = type
  165. if (value)
  166. this.value = value
  167. },
  168.  
  169. error(name='') {
  170. let slice = this.string.slice(this.index < 6 ? 0 : this.index - 6, this.index + 5)
  171. this.move()
  172. return new this.Lexeme('error',//
  173. `Error${name && (': ' + name + ' ')}\n at char ${this.index} (${slice})`)
  174. },
  175.  
  176. getLexeme() {
  177. while (this.isWhitespace(this.char))
  178. this.move()
  179. this.startIndex = this.index
  180.  
  181. if (!this.char) {
  182. if (this.finished)
  183. return null
  184. this.finished = true
  185. return new this.Lexeme('◁')
  186. }
  187.  
  188. if (this.isDigit(this.char)) {
  189. while (this.isDigit(this.char))
  190. this.move()
  191.  
  192. if (this.isLetter(this.char))
  193. return this.error('malformed number')
  194.  
  195. return new this.Lexeme(textNumber,+this.slice)
  196. }
  197. if (this.isLetter(this.char)) {
  198. while (this.isLetter(this.char) || this.isDigit(this.char))
  199. this.move()
  200. if (this.words.includes(this.slice))
  201. return new this.Lexeme(this.slice)
  202. return new this.Lexeme(textVar,this.slice)
  203. }
  204. this.move()
  205. if (this.words.includes(this.slice)) {
  206. return new this.Lexeme(this.slice)
  207. }
  208. this.move()
  209. if (this.words.includes(this.slice)) {
  210. return new this.Lexeme(this.slice)
  211. }
  212. return this.error('unknown character')
  213.  
  214. },
  215.  
  216. [Symbol.iterator]: function*() {
  217. for (let lexeme = this.getLexeme(); lexeme; lexeme = this.getLexeme()) {
  218. yield lexeme
  219. }
  220. },
  221.  
  222. reset() {
  223. this.index = 0
  224. this.finished = false
  225. return this
  226. },
  227. }
  228.  
  229. //lexer.string = lexer.string.replace(/(?<=\W|^)\s+|\s+(?=\W|$)/g,'')
  230.  
  231. log(lexer)
  232. a = [...lexer]
  233. log(a)
  234.  
  235.  
  236. rules = textRules.split('\n')//
  237. .filter(e=>e && !e.startsWith('//'))//
  238. .map(e=>e.split('::='))//
  239. .flatMap(([k,v])=>v.split('|').map(e=>[k, e]))//
  240. .map(([k,v],i)=>({
  241. index: i,
  242. from: k.trim(),
  243. to: v.split(/\s+/).filter(Boolean)
  244. }))
  245.  
  246. void function() {
  247. let Rule = class Rule {
  248. toString() {
  249. return `#${this.index} ${this.from} → ${this.to.join(' ')}`
  250. }
  251. toJSON() {
  252. return `#${this.index} ${this.from} → ${this.to.join(' ')} `
  253. }
  254. }
  255. rules.map(e=>Object.setPrototypeOf(e, Rule.prototype))
  256. }()
  257.  
  258. log(rules)
  259. s = rules.map(e=>e.from).unique()
  260. a = rules.flatMap(e=>e.to).unique().filter(e=>!s.includes(e))
  261. types = a.concat(s).unique()
  262. words = a.filter(e=>!e.match(/<.*>/))
  263.  
  264. nlist = s
  265.  
  266. NonTerminal = function(type) {
  267. this.type = type
  268. }
  269. NonTerminal.prototype.isNonTerminal = true
  270.  
  271. parser = {
  272. NonTerminal,
  273. rules: rules,
  274. nlist: nlist,
  275. nonts: Object.assign({
  276. [Symbol.iterator]: function*() {
  277. yield*Object.values(this)
  278. },
  279. }, Object.fromEntries(nlist.map(e=>[e, new NonTerminal(e)]))),
  280.  
  281. calcFirstOfNont(n) {
  282. for (let r of n.rules)
  283. if (r.nullable)
  284. n.nullable = true
  285. return n.first = n.rules.flatMap(r=>this.calcFirstOfRule(r)).unique()
  286. },
  287. calcFirstOfRule(r) {
  288. let first = []
  289. let to = r.to.slice()
  290. // can skip nullable nonterminals
  291. while (to.length && this.nonts[to[0]] && this.nonts[to[0]].nullable)
  292. first.push(this.nonts[to.shift()].first)
  293. if (!to.length)
  294. r.nullable = true
  295. else
  296. first.push(this.nonts[to[0]] ? this.nonts[to[0]].first : [to[0]])
  297. return r.first = first.flat().unique()
  298. },
  299. calcFirsts() {
  300. for (let n of this.nonts)
  301. n.first = []
  302. for (let r of this.rules)
  303. r.first = []
  304. for (let n of this.nonts) {
  305. for (let n of this.nonts) {
  306. this.calcFirstOfNont(n)
  307. }
  308. }
  309. },
  310.  
  311. calcFollowInSeq(n, to, from) {
  312. let follow = []
  313. // to is whatever goes after this nonterminal in rule
  314. while (this.nonts[to[0]] && this.nonts[to[0]].nullable)
  315. follow.push(this.nonts[to.shift()].first)
  316.  
  317. if (!to.length)
  318. // all are nullable, going up
  319. follow.push(this.nonts[from].follow)
  320. else
  321. follow.push(this.nonts[to[0]] ? this.nonts[to[0]].first : [to[0]])
  322.  
  323. return follow.flat().unique()
  324.  
  325. },
  326. calcFollowOfNont(n) {
  327. // find possible first values after nullable nonterminal
  328. // if (!n.nullable)
  329. // return;
  330.  
  331. let follow = rules.flatMap(r=>r.to.map((e,i,a)=>e == n.type && a.slice(i + 1)).filter(Boolean).flatMap(to=>this.calcFollowInSeq(n, to, r.from)))
  332.  
  333. return n.follow = follow.concat(n.start ? [null] : []).flat().unique()
  334. },
  335. calcFollows() {
  336. for (let n of this.nonts)
  337. n.follow = []
  338. this.nonts[textStart].start = true
  339. for (let n of this.nonts)
  340. for (let n of this.nonts)
  341. this.calcFollowOfNont(n)
  342. },
  343.  
  344. calcChoiceOfRule(r) {
  345. return r.choice = !r.nullable ? r.first : r.first.concat(this.nonts[r.from].follow).unique()
  346. },
  347. calcChoiceOfNont(n) {
  348. let choice = n.rules.flatMap(e=>e.choice)
  349. if (choice.unique().length != choice.length) {
  350.  
  351. if (n.rules.length == 2 && n.rules.find(e=>!e.to.length)) {
  352. console.warn('choice is not strict, choosing longer', n.type, ...n.rules.flatMap(e=>[e, e.choice]))
  353. let short = n.rules.find(r=>!r.to.length)
  354. let long = n.rules.find(r=>r.to.length)
  355. short.choice = short.choice.filter(e=>!long.choice.includes(e))
  356. short = short
  357. } else {
  358. console.error(n, n.n, n.rules.map(e=>e.choice))
  359. throw new Error('choice is not strict')
  360. }
  361.  
  362. }
  363.  
  364. return n.choice = Object.fromEntries(n.rules.flatMap(r=>r.choice.map(c=>[c, r])))
  365. },
  366. calcChoice() {
  367. for (let r of this.rules)
  368. this.calcChoiceOfRule(r)
  369. for (let n of this.nonts)
  370. this.calcChoiceOfNont(n)
  371. },
  372.  
  373. calcTable() {
  374. let terminals = parser.rules.flatMap(e=>e.to).filter(e=>!parser.nonts[e]).unique();
  375. terminals.push('◁')
  376. let stackSymbols = Object.keys(this.nonts).concat()
  377. let stackTerminals = parser.rules.map(e=>e.to.slice(1)).flat().filter(e=>!parser.nonts[e]).unique()
  378. stackSymbols = stackSymbols.concat(stackTerminals, ['◁'])
  379.  
  380. log(stackSymbols)
  381.  
  382. let row = ()=>Object.fromEntries(terminals.map(k=>[k, null]))
  383.  
  384. let table = Object.fromEntries(stackSymbols.map(k=>[k, row()]))
  385. for (let k of stackTerminals) {
  386. table[k][k] = -1
  387. }
  388. table['◁']['◁'] = 'Допустить'
  389.  
  390. for (let rule of this.rules) {
  391. for (let c of rule.choice) {
  392. let v = table[rule.from][c || '◁']
  393. table[rule.from][c || '◁'] = v ? v + ' ' + rule.index : rule.index
  394. }
  395. }
  396.  
  397. console.table(Object.fromEntries(Object.entries(table).map(([k,v])=>[k,Object.fromEntries(Object.entries(v).map(([k2,v2])=>[k2,typeof v2=='number'&&v2>-1?v2+1:v2]))])))
  398. this.table = table
  399. },
  400.  
  401. init() {
  402. for (let n of this.nonts)
  403. n.rules = this.rules.filter(e=>e.from == n.type)
  404. this.calcFirsts()
  405. this.calcFollows()
  406. this.calcChoice()
  407. this.calcTable()
  408. return this
  409. },
  410.  
  411. parseStep(l, stack) {
  412.  
  413. let v = stack.pop()
  414. let rn = this.table[v][l.type]
  415.  
  416. let r = this.rules[rn] || []
  417. let to = r.to
  418.  
  419. log(l, v, stack.slice().reverse(), r + '', to && to.slice().reverse())
  420.  
  421. if (rn == 'Допустить')
  422. return true
  423.  
  424. if (rn == -1) {
  425. return true
  426. // next lexeme
  427. }
  428.  
  429. if (rn == null) {
  430. console.error('error', v, l.type, l, stack)
  431. return true
  432. }
  433.  
  434. if (!to.length)
  435. return false
  436.  
  437. if (this.nonts[to[0]]) {
  438. // nont
  439. to.slice().reverse().map(e=>stack.push(e))
  440. return false
  441. } else {
  442. to.slice(1).reverse().map(e=>stack.push(e))
  443. return true
  444. }
  445.  
  446. },
  447.  
  448. parse() {
  449. lexer.reset()
  450.  
  451. let stack = ['◁', textStart]
  452.  
  453. while (!lexer.finished && stack.length) {
  454. let l = lexer.getLexeme()
  455. while (!this.parseStep(l, stack))
  456. ;
  457. }
  458.  
  459. },
  460. }
  461.  
  462. parser.init()
  463.  
  464. parser.parse()
  465. // r = Object.fromEntries(Object.entries(parser.rules).filter(([k,v])=>k != 'rules')//
  466. // .map(([k,v])=>[k, Object.fromEntries(Object.entries(v).map(([k,v])=>[k, typeof v == 'object' ? (''+v) : v]))]))
  467. // console.table(r)
  468.  
  469. // r = Object.fromEntries(Object.entries(parser.nonts).filter(([k,v])=>k != 'rules')//
  470. // .map(([k,v])=>[k, Object.fromEntries(Object.entries(v).map(([k,v])=>[k, typeof v == 'object' ? (''+v) : v]))]))
  471. // console.table(r)
  472.  
  473. // console.table(Object.fromEntries([...parser.nonts].map(e=>[e.type, Object.fromEntries(Object.entries(e.choice).map(([k,v])=>[k, v && (v + '')]))])))
  474.  
  475. r = parser.rules.map(r=>[r.from + ' ::= ' + r.to.join(' '),r])//
  476. .map(([s,r])=>(s+' '.repeat(60)).slice(0,60)+s.slice(60) + ' >>> ' +r.choice.map(e=>e||'END_OF_FILE').join(' ')).join('\n')
  477. console.log(r)
  478.  
  479. parser
  480.  
  481.  
  482. r = parser.rules.map(r=>[(' '+(1+r.index)).slice(-2) + ' ' + r.from + ' ::= ' + r.to.join(' ')])//
  483. //.map(([s,r])=>s + '\n\t\t ' +r.choice.map(e=>e||'END_OF_FILE').join(' '))
  484. .join('\n')
  485. console.log(r)
  486.  
  487. r = parser.rules.map(r=>'Выбор(' + (' '+(1+r.index)).slice(-2) + ') = { ' + r.choice.map(e=>e||'⊥').join(' , ') + ' }').join('\n')
  488. console.log(r)
  489.  
  490. // r = parser.rules.map(r=>[(' #'+(1+r.index)).slice(-3) + ' ' + r.to.join(' '),!!parser.nonts[r.to[0]]])//
  491. // .map(([s,r])=>s + ' ' + r).join('\n')
  492. // console.log(r)
  493. parser.rules.map(r=>r.hold = !r.to[0] || parser.nonts[r.to[0]])
  494. r = parser.rules.map(r=>[r, r.hold ? `Заменить( ${r.to.join(' ')} ), Держать` : `Заменить( ${r.to.slice(1).join(' ')} ), Сдвиг`])//
  495. .map(([r,s])=>` #${r.index+1} `.slice(-4) + s.replace('Заменить( ),','Вытолк,')) //
  496. .join('\n')
  497. console.log(r)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement