PageRenderTime 47ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/library/parse/example/scalc/scalc.y

http://github.com/gobo-eiffel/gobo
Happy | 300 lines | 267 code | 33 blank | 0 comment | 0 complexity | 0b152187660c8f55da055a04fb1e5e5e MD5 | raw file
  1. %{
  2. note
  3. description:
  4. "Scientific calculator"
  5. copyright: "Copyright (c) 2019, Eric Bezault and others"
  6. license: "MIT License"
  7. date: "$Date$"
  8. revision: "$Revision$"
  9. class SCALC
  10. inherit
  11. YY_PARSER_SKELETON
  12. rename
  13. make as make_parser_skeleton
  14. end
  15. create
  16. make, execute
  17. %}
  18. -- geyacc declarations.
  19. %token <DOUBLE> NUM -- Double precision number
  20. %token <DOUBLE> PI "pi: π" -- 3.141592
  21. %token <STRING> VAR -- Memory name
  22. %type <DOUBLE> exp
  23. %right ASSIGNMENT -- Assignment sign `:='
  24. %left '-' '+'
  25. %left '*' '/'
  26. %left NEG -- negation--unary minus
  27. %left '√' -- square root
  28. %right '^' -- exponentiation
  29. %%
  30. input: -- Empty
  31. | input line
  32. ;
  33. line: '\n'
  34. | exp '\n' { print ($1); print ("%N") }
  35. | error '\n' { recover }
  36. ;
  37. exp: NUM { $$ := $1 }
  38. | "pi: π" { $$ := {DOUBLE} 3.141592 }
  39. | VAR { $$ := memory_value ($1) }
  40. | VAR ASSIGNMENT exp { $$ := $3; set_memory_value ($$, $1) }
  41. | exp '+' exp { $$ := $1 + $3 }
  42. | exp '-' exp { $$ := $1 - $3 }
  43. | exp '*' exp { $$ := $1 * $3 }
  44. | exp '/' exp { $$ := $1 / $3 }
  45. | '-' exp %prec NEG { $$ := -$2 }
  46. | '√' exp { $$ := Current √ $2 }
  47. | '(' exp ')' { $$ := $2 }
  48. ;
  49. %%
  50. feature {NONE} -- Initialization
  51. make
  52. -- Create a new scientific calculator.
  53. do
  54. make_parser_skeleton
  55. last_string_value := ""
  56. create memory_values.make (10)
  57. end
  58. execute
  59. -- Run calculator.
  60. do
  61. make
  62. parse
  63. end
  64. feature -- Operators
  65. square_root alias "√" (d: DOUBLE): DOUBLE
  66. -- Square root of `d', or 0.0 if negative.
  67. -- Use the Unicode alias .
  68. do
  69. if d >= 0.0 then
  70. Result := {DOUBLE_MATH}.sqrt (d)
  71. else
  72. Result := 0.0
  73. end
  74. end
  75. feature -- Memory management
  76. memory_value (a_name: STRING): DOUBLE
  77. -- Value associated with memory a_name;
  78. -- 0.0 if no value has been stored in a_name yet
  79. require
  80. a_name_not_void: a_name /= Void
  81. do
  82. if memory_values.has (a_name) then
  83. Result := memory_values.item (a_name)
  84. else
  85. Result := 0.0
  86. end
  87. end
  88. set_memory_value (a_value: DOUBLE; a_name: STRING)
  89. -- Store a_value into a_name.
  90. require
  91. a_name_not_void: a_name /= Void
  92. do
  93. memory_values.force (a_value, a_name)
  94. ensure
  95. memory_value_set: memory_value (a_name) = a_value
  96. end
  97. feature {NONE} -- Scanner
  98. read_token
  99. -- Lexical analyzer returns a double floating point
  100. -- number on the stack and the token NUM, a STRING and
  101. -- and the token VAR, a token ASSIGNMENT, or the
  102. -- character read if not a number. Skips all blanks
  103. -- and tabs, returns 0 for EOF.
  104. local
  105. c: CHARACTER
  106. buffer: STRING
  107. do
  108. -- Skip white space
  109. from
  110. if has_pending_character then
  111. c := pending_character
  112. has_pending_character := False
  113. elseif not std.input.end_of_file then
  114. std.input.read_character
  115. c := std.input.last_character
  116. end
  117. until
  118. std.input.end_of_file or else
  119. (c /= ' ' and c /= '%T')
  120. loop
  121. std.input.read_character
  122. c := std.input.last_character
  123. end
  124. if std.input.end_of_file then
  125. -- Return end-of-file
  126. last_token := 0
  127. else
  128. inspect c
  129. when '0'..'9' then
  130. -- Process numbers
  131. last_token := NUM
  132. from
  133. create buffer.make (10)
  134. buffer.append_character (c)
  135. std.input.read_character
  136. c := std.input.last_character
  137. until
  138. std.input.end_of_file or else
  139. (c < '0' or c > '9')
  140. loop
  141. buffer.append_character (c)
  142. std.input.read_character
  143. c := std.input.last_character
  144. end
  145. if not std.input.end_of_file and then c = '.' then
  146. from
  147. buffer.append_character ('.')
  148. std.input.read_character
  149. c := std.input.last_character
  150. until
  151. std.input.end_of_file or else
  152. (c < '0' or c > '9')
  153. loop
  154. buffer.append_character (c)
  155. std.input.read_character
  156. c := std.input.last_character
  157. end
  158. end
  159. if not std.input.end_of_file then
  160. pending_character := c
  161. has_pending_character := True
  162. end
  163. last_double_value := buffer.to_double
  164. when 'a'..'z', 'A'..'Z' then
  165. -- Process variables.
  166. last_token := VAR
  167. from
  168. create buffer.make (10)
  169. buffer.append_character (c)
  170. std.input.read_character
  171. c := std.input.last_character
  172. until
  173. std.input.end_of_file or else
  174. not (('a' <= c and c <= 'z') or
  175. ('A' <= c and c <= 'Z') or
  176. ('0' <= c and c <= '9'))
  177. loop
  178. buffer.append_character (c)
  179. std.input.read_character
  180. c := std.input.last_character
  181. end
  182. if not std.input.end_of_file then
  183. pending_character := c
  184. has_pending_character := True
  185. end
  186. last_string_value := buffer
  187. when ':' then
  188. std.input.read_character
  189. c := std.input.last_character
  190. if not std.input.end_of_file then
  191. if c = '=' then
  192. -- Found ":="
  193. last_token := ASSIGNMENT
  194. else
  195. -- Return single character
  196. last_token := (':').code
  197. pending_character := c
  198. has_pending_character := True
  199. end
  200. else
  201. -- Return single character
  202. last_token := (':').code
  203. end
  204. when '%/207/' then
  205. std.input.read_character
  206. c := std.input.last_character
  207. if not std.input.end_of_file then
  208. if c = '%/128/' then
  209. -- UTF-8 encoding for 'π'.
  210. last_token := PI
  211. else
  212. -- Return single character
  213. last_token := ('%/207/').code
  214. pending_character := c
  215. has_pending_character := True
  216. end
  217. else
  218. -- Return single character
  219. last_token := ('%/207/').code
  220. end
  221. when '%/226/' then
  222. std.input.read_character
  223. c := std.input.last_character
  224. if not std.input.end_of_file then
  225. if c = '%/136/' then
  226. std.input.read_character
  227. c := std.input.last_character
  228. if not std.input.end_of_file then
  229. if c = '%/154/' then
  230. -- UTF-8 encoding for '√'.
  231. last_token := ({CHARACTER_32} '√').code
  232. else
  233. -- Unsupported Unicode character.
  234. last_token := -1
  235. end
  236. else
  237. -- Return single character
  238. last_token := ('%/226/').code
  239. pending_character := '%/136/'
  240. has_pending_character := True
  241. end
  242. else
  243. -- Return single character
  244. last_token := ('%/226/').code
  245. pending_character := c
  246. has_pending_character := True
  247. end
  248. else
  249. -- Return single character
  250. last_token := ('%/226/').code
  251. end
  252. else
  253. -- Return single character
  254. last_token := c.code
  255. end
  256. end
  257. end
  258. last_token: INTEGER
  259. -- Last token read
  260. feature {NONE} -- Implementation
  261. pending_character: CHARACTER
  262. has_pending_character: BOOLEAN
  263. memory_values: DS_HASH_TABLE [DOUBLE, STRING]
  264. -- Values already stored so far
  265. invariant
  266. memory_values_not_void: memory_values /= Void
  267. end