bairui

Jack Crenshaw's Compiler Tutorial in VimL, part 3.

Jun 26th, 2011
294
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
VIM 3.08 KB | None | 0 0
  1. " Jack Crenshaw's "Let's Build a Compiler", Part III: More Expressions
  2. " Barry Arthur  Jun 26, 2011
  3. "
  4. " This translator converts expressions of the form:
  5. "   x = (-B()+a)-5/9*2
  6. " Into:
  7. "   let x = (-B()+a)-5/9*2
  8. "
  9. " In and of itself not terribly amazing, agreed, but the value is in the how,
  10. " not the what.
  11.  
  12. function! GetChar()
  13.  let s:look = strpart(s:input, s:pos, 1)
  14.  let s:pos += 1
  15. endfunction
  16.  
  17. function! Error(msg)
  18.  echoerr "Error: " . a:msg . "."
  19. endfunction
  20.  
  21. function! Abort(msg)
  22.  call Error(a:msg)
  23. endfunction
  24.  
  25. function! Expected(msg)
  26.  call Abort(a:msg . ' Expected')
  27. endfunction
  28.  
  29. function! Match(c)
  30.  if s:look == a:c
  31.    call GetChar()
  32.  else
  33.    call Expected("'" . a:c . "'")
  34.  endif
  35. endfunction
  36.  
  37. function! IsAddop(c)
  38.  return index(['+', '-'], a:c) != -1
  39. endfunction
  40.  
  41. function! IsAlpha(c)
  42.  return match(a:c, '[A-Z]') != -1
  43. endfunction
  44.  
  45. function! IsDigit(c)
  46.  return match(a:c, '[0-9]') != -1
  47. endfunction
  48.  
  49. function! GetName()
  50.  if !IsAlpha(s:look)
  51.    call Expected('Name')
  52.  endif
  53.  let retval = tolower(s:look)
  54.  call GetChar()
  55.  return retval
  56. endfunction
  57.  
  58. function! GetNum()
  59.  if !IsDigit(s:look)
  60.    call Expected('Integer')
  61.  endif
  62.  let retval = s:look
  63.  call GetChar()
  64.  return retval
  65. endfunction
  66.  
  67. function! Emit(code)
  68.  let s:output .= a:code
  69. endfunction
  70.  
  71. function! Init(input)
  72.  let s:look = ''
  73.  let s:input = a:input
  74.  let s:output = ''
  75.  let s:pos = 0
  76.  call GetChar()
  77. endfunction
  78.  
  79. function! Ident()
  80.  let name = GetName()
  81.  if s:look == '('
  82.    call Match('(')
  83.    call Match(')')
  84.    call Emit(toupper(name) . '()')
  85.  else
  86.    call Emit(name)
  87.  endif
  88. endfunction
  89.  
  90. function! Factor()
  91.  if s:look == '('
  92.    call Match('(')
  93.    call Emit('(')
  94.    call Expression()
  95.    call Match(')')
  96.    call Emit(')')
  97.  elseif IsAlpha(s:look)
  98.    call Ident()
  99.  else
  100.    call Emit(GetNum())
  101.  endif
  102. endfunction
  103.  
  104. function! Multiply()
  105.  call Match('*')
  106.  call Emit('*')
  107.  call Factor()
  108. endfunction
  109.  
  110. function! Divide()
  111.  call Match('/')
  112.  call Emit('/')
  113.  call Factor()
  114. endfunction
  115.  
  116. function! Term()
  117.  call Factor()
  118.  while index(['*', '/'], s:look) != -1
  119.    if s:look == '*'
  120.      call Multiply()
  121.    elseif s:look == '/'
  122.      call Divide()
  123.    endif
  124.  endwhile
  125. endfunction
  126.  
  127. function! Add()
  128.  call Match('+')
  129.  call Emit('+')
  130.  call Term()
  131. endfunction
  132.  
  133. function! Subtract()
  134.  call Match('-')
  135.  call Emit('-')
  136.  call Term()
  137. endfunction
  138.  
  139. function! Expression()
  140.  if IsAddop(s:look)
  141.    call Emit(s:look)
  142.    call GetChar()
  143.    call Expression()
  144.  else
  145.    call Term()
  146.    while IsAddop(s:look)
  147.      if s:look == '+'
  148.        call Add()
  149.      elseif s:look == '-'
  150.        call Subtract()
  151.      endif
  152.    endwhile
  153.  endif
  154. endfunction
  155.  
  156. function! Assignment()
  157.  let name = GetName()
  158.  call Match('=')
  159.  call Emit('let ' . name . ' = ')
  160.  call Expression()
  161. endfunction
  162.  
  163. function! Parse(input)
  164.  call Init(a:input)
  165.  call Assignment()
  166.  if s:look != "\n"
  167.    call Expected('Newline')
  168.  else
  169.    return s:output
  170.  endif
  171. endfunction
  172.  
  173. " Test
  174. echo Parse("x=(-B()+A)-5/9*2\n")
Advertisement
Add Comment
Please, Sign In to add comment