rpl-edb.el 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. ;;; rpl-edb.el -- utilities to parse the entries database
  2. ;; Copyright (C) 2014 Paul Onions
  3. ;; Author: Paul Onions <paul.onions@acm.org>
  4. ;; Keywords: RPL, UserRPL, SysRPL, HP48, HP49, HP50
  5. ;; This file is free software, see the LICENCE file in this directory
  6. ;; for copying terms.
  7. ;;; Commentary:
  8. ;; Functions to parse the entries.db file.
  9. ;;; Code:
  10. (require 'cl-lib)
  11. (defun rpl-edb-get-line ()
  12. "Get line that point is on from the current buffer.
  13. Return a string containing the line, or nil if at end of buffer.
  14. As a side-effect set point to the start of the next line."
  15. (cond ((eobp)
  16. nil)
  17. (t
  18. (beginning-of-line)
  19. (let ((start (point)))
  20. (end-of-line)
  21. (let ((line (buffer-substring-no-properties start (point))))
  22. (forward-char)
  23. line)))))
  24. ;;; Parsing identifier lines
  25. ;;;
  26. (defun rpl-edb-consume-ident-line ()
  27. "Consume an EDB identifier line.
  28. Return a list of two strings: the identifier and its stack effect
  29. description. Move point to the start of the next line."
  30. (let ((line (rpl-edb-get-line)))
  31. (cond ((string-match "^[[:graph:]]+" line)
  32. (let* ((name (match-string 0 line))
  33. (desc (substring line (match-end 0))))
  34. ;; Automatically consume continuation lines
  35. ;; (after line ends with a backslash)
  36. (while (and (> (length desc) 0)
  37. (string-match ".*\\\\[[:blank:]]*$" desc))
  38. (setq desc (concat (substring desc 0 (1- (length desc)))
  39. "\n"
  40. (rpl-edb-get-line))))
  41. (list name desc)))
  42. (t
  43. (list "" "")))))
  44. ;;; Parsing keyword lines
  45. ;;;
  46. (defun rpl-edb-parse-keyword-line (line)
  47. "Parse the given EDB keyword line.
  48. Return a list consisting of the EDB keyword as a keyword symbol
  49. and a parameter string (to be further parsed later)."
  50. (cond ((string-match "\\.[[:blank:]]+\\([[:alnum:]]+\\):" line)
  51. (let ((keyword (intern (concat ":" (match-string 1 line))))
  52. (param-str (substring line (match-end 0))))
  53. (list keyword param-str)))
  54. (t
  55. (list nil ""))))
  56. (defun rpl-edb-parse-calc-param-str (str)
  57. (cond ((string-match "[[:blank:]]*\\([[:alnum:]]+\\)[[:blank:]]*\\(\\\\\\([[:graph:]]+?\\)\\\\\\)?" str)
  58. (let ((addr (match-string 1 str))
  59. (fmt (match-string 3 str))
  60. (flags nil))
  61. (setq str (substring str (match-end 0)))
  62. (while (string-match "[[:blank:]]*\\[\\([[:graph:]]+\\)\\]" str)
  63. (setq flags (cons (intern (concat ":" (match-string 1 str))) flags))
  64. (setq str (substring str (match-end 1))))
  65. (list addr fmt (reverse flags))))
  66. (t
  67. (list "" "" nil))))
  68. (defun rpl-edb-parse-aka-param-str (str)
  69. (let ((names nil))
  70. (while (string-match "[[:blank:]]*\\([[:graph:]]+\\)" str)
  71. (setq names (cons (match-string 1 str) names))
  72. (setq str (substring str (match-end 1))))
  73. (reverse names)))
  74. (defun rpl-edb-consume-keyword-line ()
  75. (let ((line (rpl-edb-get-line)))
  76. (cl-destructuring-bind (keyword param-str)
  77. (rpl-edb-parse-keyword-line line)
  78. (cond ((member keyword '(:38G :39G :48G :49G))
  79. (cl-destructuring-bind (addr fmt flags)
  80. (rpl-edb-parse-calc-param-str param-str)
  81. (append (list keyword addr fmt) flags)))
  82. ((eql keyword :AKA)
  83. (let ((names (rpl-edb-parse-aka-param-str param-str)))
  84. (cons keyword names)))
  85. (t
  86. (error "Illegal EDB keyword, %s" keyword))))))
  87. ;;; Parsing extended description lines
  88. ;;;
  89. (defun rpl-edb-consume-description-line ()
  90. "Consume an EDB extended description line.
  91. Return a string. Move point to the start of the next line."
  92. (let ((line (rpl-edb-get-line)))
  93. (substring line 80)))
  94. ;;; Parsing the entries.db buffer
  95. ;;;
  96. (defun rpl-edb-parse-buffer ()
  97. "Parse the current buffer, assumed to be the entries.db file.
  98. Return a list of EDB entries of the format:
  99. ???
  100. "
  101. (interactive)
  102. (let ((entry-names nil)
  103. (entry-stack-effect nil)
  104. (entry-calc-infos nil)
  105. (entry-description "")
  106. (entries nil))
  107. (beginning-of-buffer)
  108. (while (not (eobp))
  109. (cond ((eql (char-after) ?*)
  110. ;; A comment line -- ignore it
  111. (forward-line))
  112. ((eql (char-after) ?@)
  113. ;; A directive -- ignore it
  114. (forward-line))
  115. ((eql (char-after) ?\;)
  116. ;; An extended description line
  117. (setq entry-description (concat entry-description " "
  118. (rpl-edb-consume-description-line))))
  119. ((eql (char-after) ?.)
  120. ;; A keyword line
  121. (cl-destructuring-bind (keyword &rest params)
  122. (rpl-edb-consume-keyword-line)
  123. (cond ((eql keyword :AKA)
  124. (dolist (name params)
  125. (push name entry-names)))
  126. (t
  127. (push (cons keyword params) entry-calc-infos)))))
  128. (t
  129. ;; An identifier/stack-effect line
  130. (when entry-names
  131. (push (list entry-names entry-stack-effect entry-calc-infos entry-description) entries))
  132. (cl-destructuring-bind (name stack-effect)
  133. (rpl-edb-consume-ident-line)
  134. (setq entry-names (list name))
  135. (setq entry-stack-effect stack-effect)
  136. (setq entry-calc-infos nil)
  137. (setq entry-description "")))))
  138. (when entry-names
  139. (push (list entry-names entry-stack-effect entry-calc-infos entry-description) entries))
  140. (reverse entries)))
  141. (defvar rpl-edb-entries nil
  142. "A place on which to push the parsed entries.")