Compiler/lexical analyzer: Difference between revisions
Content added Content deleted
m (minor edits) |
m (Fix a bug in make-this-or-that-handler and use lisp keywords instead of obscure symbols.) |
||
Line 1,677: | Line 1,677: | ||
do (setf may-end (char= ch #\*)) |
do (setf may-end (char= ch #\*)) |
||
finally (return (read stream t nil t)))) |
finally (return (read stream t nil t)))) |
||
(t (make-token :name |
(t (make-token :name :op-divide :line (line-of stream) :column (column-of stream))))) |
||
(defun make-constant-handler (token-name) |
(defun make-constant-handler (token-name) |
||
Line 1,693: | Line 1,693: | ||
(read-char stream nil nil t) |
(read-char stream nil nil t) |
||
(make-token :name then :line line :column column)) |
(make-token :name then :line line :column column)) |
||
( |
(else |
||
(make-token :name else :line line :column column)) |
|||
(t |
|||
(lexer-error "Unrecognized character '~A'" next)))))) |
|||
(defun identifier? (symbol) |
(defun identifier? (symbol) |
||
Line 1,709: | Line 1,711: | ||
(defun id->keyword (id line column) |
(defun id->keyword (id line column) |
||
(case id |
(case id |
||
(|if| (make-token :name |
(|if| (make-token :name :keyword-if :line line :column column)) |
||
(|else| (make-token :name |
(|else| (make-token :name :keyword-else :line line :column column)) |
||
(|while| (make-token :name |
(|while| (make-token :name :keyword-while :line line :column column)) |
||
(|print| (make-token :name |
(|print| (make-token :name :keyword-print :line line :column column)) |
||
(|putc| (make-token :name |
(|putc| (make-token :name :keyword-putc :line line :column column)) |
||
(t nil))) |
(t nil))) |
||
Line 1,725: | Line 1,727: | ||
(if (identifier? obj) |
(if (identifier? obj) |
||
(or (id->keyword obj line column) |
(or (id->keyword obj line column) |
||
(make-token :name |
(make-token :name :identifier :value obj :line line :column column)) |
||
(lexer-error "Invalid identifier name: ~A" obj)))))) |
(lexer-error "Invalid identifier name: ~A" obj)))))) |
||
Line 1,736: | Line 1,738: | ||
(let ((obj (read stream t nil t))) |
(let ((obj (read stream t nil t))) |
||
(if (integerp obj) |
(if (integerp obj) |
||
(make-token :name |
(make-token :name :integer :value obj :line line :column column) |
||
(lexer-error "Invalid integer: ~A" obj)))))) |
(lexer-error "Invalid integer: ~A" obj)))))) |
||
Line 1,754: | Line 1,756: | ||
(t ch)))) |
(t ch)))) |
||
(if (char= #\' (read-char stream t nil t)) |
(if (char= #\' (read-char stream t nil t)) |
||
(make-token :name |
(make-token :name :integer :value (char-code parsed) :line line :column column) |
||
(lexer-error "Only one character is allowed in character literal")))) |
(lexer-error "Only one character is allowed in character literal")))) |
||
Line 1,773: | Line 1,775: | ||
(t ch))) |
(t ch))) |
||
(vector-push-extend ch result) |
(vector-push-extend ch result) |
||
finally (return (make-token :name |
finally (return (make-token :name :string :value result :line line :column column)))) |
||
(defun make-lexer-readtable () |
(defun make-lexer-readtable () |
||
Line 1,783: | Line 1,785: | ||
;; operators |
;; operators |
||
(set-macro-character #\* (make-constant-handler |
(set-macro-character #\* (make-constant-handler :op-multiply)) |
||
(set-macro-character #\/ #'handle-divide-or-comment) |
(set-macro-character #\/ #'handle-divide-or-comment) |
||
(set-macro-character #\% (make-constant-handler |
(set-macro-character #\% (make-constant-handler :op-mod)) |
||
(set-macro-character #\+ (make-constant-handler |
(set-macro-character #\+ (make-constant-handler :op-add)) |
||
(set-macro-character #\- (make-constant-handler |
(set-macro-character #\- (make-constant-handler :op-subtract)) |
||
(set-macro-character #\< (make-this-or-that-handler #\= |
(set-macro-character #\< (make-this-or-that-handler #\= :op-lessequal :op-less)) |
||
(set-macro-character #\> (make-this-or-that-handler #\= |
(set-macro-character #\> (make-this-or-that-handler #\= :op-greaterequal :op-greater)) |
||
(set-macro-character #\= (make-this-or-that-handler #\= |
(set-macro-character #\= (make-this-or-that-handler #\= :op-equal :op-assign)) |
||
(set-macro-character #\! (make-this-or-that-handler #\= |
(set-macro-character #\! (make-this-or-that-handler #\= :op-notequal :op-not)) |
||
(set-macro-character #\& (make-this-or-that-handler #\& |
(set-macro-character #\& (make-this-or-that-handler #\& :op-and)) |
||
(set-macro-character #\| (make-this-or-that-handler #\| |
(set-macro-character #\| (make-this-or-that-handler #\| :op-or)) |
||
;; symbols |
;; symbols |
||
(set-macro-character #\( (make-constant-handler |
(set-macro-character #\( (make-constant-handler :leftparen)) |
||
(set-macro-character #\) (make-constant-handler |
(set-macro-character #\) (make-constant-handler :rightparen)) |
||
(set-macro-character #\{ (make-constant-handler |
(set-macro-character #\{ (make-constant-handler :leftbrace)) |
||
(set-macro-character #\} (make-constant-handler |
(set-macro-character #\} (make-constant-handler :rightbrace)) |
||
(set-macro-character #\; (make-constant-handler |
(set-macro-character #\; (make-constant-handler :semicolon)) |
||
(set-macro-character #\, (make-constant-handler |
(set-macro-character #\, (make-constant-handler :comma)) |
||
;; identifiers & keywords |
;; identifiers & keywords |
||
Line 1,830: | Line 1,832: | ||
(token-line token) (token-column token) (token-name token) (token-value token)) |
(token-line token) (token-column token) (token-name token) (token-value token)) |
||
finally (format t "~5D ~5D ~15A~%" |
finally (format t "~5D ~5D ~15A~%" |
||
(line-of stream) (column-of stream) |
(line-of stream) (column-of stream) :end-of-input) |
||
(close stream)))) |
(close stream)))) |
||
Line 1,845: | Line 1,847: | ||
(if file |
(if file |
||
(lex file) |
(lex file) |
||
(error "File must be specified")))) |
(error "File must be specified"))))</lang> |
||
</lang> |
|||
{{out|case=test case 3}} |
{{out|case=test case 3}} |
||
<pre> 5 16 |
<pre> 5 16 KEYWORD-PRINT |
||
5 40 |
5 40 OP-SUBTRACT |
||
6 16 |
6 16 KEYWORD-PUTC |
||
6 40 |
6 40 OP-LESS |
||
7 16 |
7 16 KEYWORD-IF |
||
7 40 |
7 40 OP-GREATER |
||
8 16 |
8 16 KEYWORD-ELSE |
||
8 40 |
8 40 OP-LESSEQUAL |
||
9 16 |
9 16 KEYWORD-WHILE |
||
9 40 |
9 40 OP-GREATEREQUAL |
||
10 16 |
10 16 LEFTBRACE |
||
10 40 |
10 40 OP-EQUAL |
||
11 16 |
11 16 RIGHTBRACE |
||
11 40 |
11 40 OP-NOTEQUAL |
||
12 16 |
12 16 LEFTPAREN |
||
12 40 |
12 40 OP-AND |
||
13 16 |
13 16 RIGHTPAREN |
||
13 40 |
13 40 OP-OR |
||
14 16 |
14 16 OP-SUBTRACT |
||
14 40 |
14 40 SEMICOLON |
||
15 16 |
15 16 OP-NOT |
||
15 40 |
15 40 COMMA |
||
16 16 |
16 16 OP-MULTIPLY |
||
16 40 |
16 40 OP-ASSIGN |
||
17 16 |
17 16 OP-DIVIDE |
||
17 40 |
17 40 INTEGER 42 |
||
18 16 |
18 16 OP-MOD |
||
18 40 |
18 40 STRING "String literal" |
||
19 16 |
19 16 OP-ADD |
||
19 40 |
19 40 IDENTIFIER variable_name |
||
20 26 |
20 26 INTEGER 10 |
||
21 26 |
21 26 INTEGER 92 |
||
22 26 |
22 26 INTEGER 32 |
||
23 1 |
23 1 END-OF-INPUT </pre> |
||
=={{header|Euphoria}}== |
=={{header|Euphoria}}== |