bairui

Jack Crenshaw's "Let's Build a Compiler", Part 3:Expressions

Jun 26th, 2011
272
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
VIM 3.72 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. "   value = (-pi() + apple) - 50 / 90 * 2
  6. " Into:
  7. "   let value = (-pi()+apple)-50/90*2
  8. "
  9. " In and of itself not terribly amazing, agreed, but the value is in the how,
  10. " not the what.
  11.  
  12. "Parser {{{1
  13. function! Error(msg) "{{{2
  14.   echoerr "Error: " . a:msg . "."
  15. endfunction
  16.  
  17. function! Expected(msg) "{{{2
  18.   call Error('Expected ' . a:msg . " at byte position " . s:pos . " but got '" . s:look . "' instead")
  19. endfunction
  20.  
  21. function! Match(c) "{{{2
  22.   if s:look == a:c
  23.     call GetChar()
  24.   else
  25.     call Expected("'" . a:c . "'")
  26.   endif
  27. endfunction
  28.  
  29. function! IsAddop(c) "{{{2
  30.   return index(['+', '-'], a:c) != -1
  31. endfunction
  32.  
  33. function! IsAlpha(c) "{{{2
  34.   return match(a:c, '[A-Z]') != -1
  35. endfunction
  36.  
  37. function! IsDigit(c) "{{{2
  38.   return match(a:c, '[0-9]') != -1
  39. endfunction
  40.  
  41. function! IsAlNum(c) "{{{2
  42.   return IsAlpha(a:c) || IsDigit(a:c)
  43. endfunction
  44.  
  45. function! IsWhite(c) "{{{2
  46.   return index([' ', "\t"], a:c) != -1
  47. endfunction
  48.  
  49. function! SkipWhite() "{{{2
  50.   while IsWhite(s:look)
  51.     call GetChar()
  52.   endwhile
  53. endfunction
  54.  
  55. function! GetChar() "{{{2
  56.   let s:look = strpart(s:input, s:pos, 1)
  57.   let s:pos += 1
  58.   call SkipWhite()
  59. endfunction
  60.  
  61. function! GetName() "{{{2
  62.   let name = ''
  63.   if !IsAlpha(s:look)
  64.     call Expected('Name')
  65.   endif
  66.   while IsAlNum(s:look)
  67.     let name .= s:look
  68.     call GetChar()
  69.   endwhile
  70.   return name
  71. endfunction
  72.  
  73. function! GetNum() "{{{2
  74.   let value = ''
  75.   if !IsDigit(s:look)
  76.     call Expected('Integer')
  77.   endif
  78.   while IsDigit(s:look)
  79.     let value .= s:look
  80.     call GetChar()
  81.   endwhile
  82.   return value
  83. endfunction
  84.  
  85. function! Emit(code) "{{{2
  86.   let s:output .= a:code
  87. endfunction
  88.  
  89. function! Init(input) "{{{2
  90.   let s:look = ''
  91.   let s:input = a:input
  92.   let s:output = ''
  93.   let s:pos = 0
  94.   call GetChar()
  95. endfunction
  96.  
  97. function! Ident() "{{{2
  98.   let name = GetName()
  99.   if s:look == '('
  100.     call Match('(')
  101.     call Match(')')
  102.     call Emit(name . '()')
  103.   else
  104.     call Emit(name)
  105.   endif
  106. endfunction
  107.  
  108. function! Factor() "{{{2
  109.   if s:look == '('
  110.     call Match('(')
  111.     call Emit('(')
  112.     call Expression()
  113.     call Match(')')
  114.     call Emit(')')
  115.   elseif IsAlpha(s:look)
  116.     call Ident()
  117.   else
  118.     call Emit(GetNum())
  119.   endif
  120. endfunction
  121.  
  122. function! Multiply() "{{{2
  123.   call Match('*')
  124.   call Emit('*')
  125.   call Factor()
  126. endfunction
  127.  
  128. function! Divide() "{{{2
  129.   call Match('/')
  130.   call Emit('/')
  131.   call Factor()
  132. endfunction
  133.  
  134. function! Term() "{{{2
  135.   call Factor()
  136.   while index(['*', '/'], s:look) != -1
  137.     if s:look == '*'
  138.       call Multiply()
  139.     elseif s:look == '/'
  140.       call Divide()
  141.     endif
  142.   endwhile
  143. endfunction
  144.  
  145. function! Add() "{{{2
  146.   call Match('+')
  147.   call Emit('+')
  148.   call Term()
  149. endfunction
  150.  
  151. function! Subtract() "{{{2
  152.   call Match('-')
  153.   call Emit('-')
  154.   call Term()
  155. endfunction
  156.  
  157. function! Expression() "{{{2
  158.   if IsAddop(s:look)
  159.     call Emit(s:look)
  160.     call GetChar()
  161.     call Expression()
  162.   else
  163.     call Term()
  164.     while IsAddop(s:look)
  165.       if s:look == '+'
  166.         call Add()
  167.       elseif s:look == '-'
  168.         call Subtract()
  169.       endif
  170.     endwhile
  171.   endif
  172. endfunction
  173.  
  174. function! Assignment() "{{{2
  175.   let name = GetName()
  176.   call Match('=')
  177.   call Emit('let ' . name . ' = ')
  178.   call Expression()
  179. endfunction
  180.  
  181.  
  182. " Driver {{{1
  183. function! ParseAssignmentExpression(input)
  184.   call Init(a:input)
  185.   call Assignment()
  186.   if s:look != ""
  187.     call Expected('EOF')
  188.   else
  189.     return s:output
  190.   endif
  191. endfunction
  192.  
  193.  
  194. " Test {{{1
  195. echo ParseAssignmentExpression("value = (-pi() + apple) - 15 / 90 * 2")
  196.  
  197. " vim: fdm=marker
Advertisement
Add Comment
Please, Sign In to add comment