Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- namespace "Analysis", ->
- "use strict"
- class @Parser
- maker = new Building.PrimeMaker
- run : (@source = '') ->
- do @compressStrings
- do @makeLexems
- do @decorateLexems
- do @generateAddlBlocks
- do @compressBlocks
- do @parseBlocks
- return @program
- compressStrings : ->
- @strings = []
- @source = @source.replace /'.*?'/g, (str) =>
- @strings.push str
- "$!#{@strings.length-1}!$"
- return
- makeLexems : ->
- @lexems = @source
- .replace(/\w+|[;\)\(]/g, ' $& ')
- .split(/\s+/)
- .clear()
- return
- replTable =
- ':=' : '=', '*' : '∙', '/' : '÷', 'in' : '∈'
- 'and' : '∧', 'or' : '∨', 'xor' : '⊕', 'not' : '¬'
- '<=' : '≤', '>=' : '≥', '<>' : '≠', '><' : '≠'
- decorateLexems : ->
- @lexems = @lexems.map (el) ->
- replTable[el.low] || el
- return
- generateAddlBlocks : ->
- # loop repeat-until
- for lexem, i in @lexems when lexem.low == 'repeat'
- @lexems.splice i+1, 0, 'begin'
- ++i
- for lexem, i in @lexems when lexem.low == 'until'
- @lexems.splice i, 0, 'end'
- ++i
- # after keywords
- keys = ['do', 'then', 'else']; n = @lexems.length
- for i in [0...n] when (lexem = @lexems[i].low) in keys
- continue if @lexems[i+1] == 'begin'
- @lexems.splice ++i, 0, 'begin'
- ++i # now i is first index after 'begin'
- conds = blocks = 0
- end = i - 1
- isBody = yes
- while isBody
- switch @lexems[++end].low
- when 'then' then ++conds
- when 'begin' then ++blocks
- when 'end' then --blocks
- when 'else'
- unless conds
- isBody = no
- else --conds
- when ';'
- isBody = no unless blocks
- @lexems.splice end, 0, ';', 'end'
- n += 2
- return
- compressBlocks : ->
- createProgram = (type, name) ->
- {type, name, sub : [], main : null}
- globName = @lexems[i+1] if ~i = @lexems.indexOf('program')
- @program = createProgram('program', globName || 'nameless')
- @links = []
- @blocks = []
- sub = /^(?:procedure|function)$/
- stack = [@program]
- for lexem, i in @lexems
- lexem = lexem.low
- if sub.test lexem
- current = createProgram(lexem, @lexems[i+1])
- stack.last.sub.push current
- stack.push current
- else if lexem is 'begin'
- {stop : i} = @compressBlock i
- stack.pop().main = @blocks.last
- return
- sepr = /\s*;\s*/
- compressBlock : (start) ->
- localLexems = []
- i = start + 1
- loop
- lexem = @lexems[i]
- break if lexem.low == 'end'
- if lexem.low == 'begin'
- {lexems, stop} = @compressBlock(i)
- i = stop
- lexem = "$#{@links.length-1}$"
- localLexems.push lexem
- ++i
- localLexems = localLexems.join(' ').split(sepr).clear()
- @links.push localLexems
- @blocks.push []
- {lexems : localLexems, stop : i}
- expandBlock : (str) ->
- return null unless str?
- if str[0] is '$'
- end = str.indexOf('$', 1)
- num = +str[1...end]
- return null if isNaN num
- @blocks[num]
- expandString : (str) ->
- return null unless str?
- str.replace /\$!.*?!\$/g, (el) =>
- end = el.lastIndexOf('!$')
- num = +el[2...end].trim()
- @strings[num]
- decList = [
- [/\s*([\(\):¬])\s*/g, '$1']
- [/\s*,\s*/g, ', ']
- [/\s*([∙=÷∈∧∨⊕≤≥≠])\s*/g,' $1 ']
- ]
- decorateStatement : (str) ->
- decList.each (pair) ->
- str = str.replace(pair[0], pair[1])
- return str
- makeGetterPrimes : (args..., def) ->
- improve = (str) =>
- @expandString @decorateStatement str
- sets = []
- for list, i in args by 2
- sets.push
- # [0..1] - temporary solution
- sign : new RegExp "\\b#{list[0..1].join('\\b.*?\\b')}\\b", 'i'
- sepr : new RegExp "\\s*\\b(?:#{list.join('|')})\\b\\s*", 'i'
- func : args[i+1]
- return (str) =>
- for st in sets when st.sign.test str
- return st.func str.split(st.sepr).clear().map (str) =>
- @expandBlock(str) || improve(str)
- return def(improve str)
- parseBlocks : ->
- getPrimes = @makeGetterPrimes(
- ['if', 'then', 'else'], maker.condition
- ['for', 'to', 'do'], maker.loopForU
- ['for', 'downto', 'do'], maker.loopForD
- ['for', 'in'], maker.loopIn
- ['while', 'do'], maker.loopWhile
- ['repeat', 'until'], maker.loopUntil
- maker.statement
- )
- for strBlock, i in @links
- for str in strBlock
- @blocks[i].push getPrimes(str)...
- # Start-end
- main = @blocks.last
- main.unshift maker.terminator('Начало')[0]
- main.push maker.terminator('Конец' )[0]
- return
Add Comment
Please, Sign In to add comment