added macros, temporarily removed some error checks
This commit is contained in:
@@ -1,8 +1,8 @@
|
|||||||
(in-package :cl-forth)
|
(in-package :cl-forth)
|
||||||
|
|
||||||
(defparameter *psuedo-identifiers*
|
(defparameter *psuedo-identifiers*
|
||||||
'(syscall-1 syscall-2 syscall-3 syscall-4 syscall-5 syscall-6)
|
'(syscall-1 syscall-2 syscall-3 syscall-4 syscall-5 syscall-6 makro son)
|
||||||
"These do not map to operations directly, but are valid to lexer")
|
"These do not map to operations that generate code directly, but are valid to lexer and parser")
|
||||||
|
|
||||||
(defparameter *identifiers* ())
|
(defparameter *identifiers* ())
|
||||||
;; '(+ - dump = ise yoksa yap eş push değiş üst rot düş döngü iken < >
|
;; '(+ - dump = ise yoksa yap eş push değiş üst rot düş döngü iken < >
|
||||||
|
|||||||
234
cl-forth.lisp
234
cl-forth.lisp
@@ -6,11 +6,8 @@
|
|||||||
(cond ((numberp sym?) :number)
|
(cond ((numberp sym?) :number)
|
||||||
((stringp sym?) :string)
|
((stringp sym?) :string)
|
||||||
((is-identifier sym?) :identifier)
|
((is-identifier sym?) :identifier)
|
||||||
(t
|
(t :unknown))))
|
||||||
;; temporary hack...
|
(list sym? :line line :col col :type type))
|
||||||
(return-from make-token
|
|
||||||
(values (list sym? :line line :col col :error t) t))))))
|
|
||||||
(values (list sym? :line line :col col :type type) nil))
|
|
||||||
|
|
||||||
(defun token-op (token)
|
(defun token-op (token)
|
||||||
(car token))
|
(car token))
|
||||||
@@ -35,12 +32,10 @@
|
|||||||
(for next-char = (peek-char nil line-stream nil nil))
|
(for next-char = (peek-char nil line-stream nil nil))
|
||||||
(until (null next-char))
|
(until (null next-char))
|
||||||
(let ((flag t))
|
(let ((flag t))
|
||||||
(cond ;; ((char= #\. next-char)
|
(cond ((char= #\| next-char)
|
||||||
;; (collect (make-token '|.| line-num col) into tokens)
|
|
||||||
;; (read-char line-stream))
|
|
||||||
((char= #\| next-char)
|
|
||||||
(read-char line-stream)
|
(read-char line-stream)
|
||||||
(collect (make-token :pipe line-num col :identifier) into tokens))
|
(collect (make-token :pipe line-num col :identifier)
|
||||||
|
into tokens))
|
||||||
((char= #\Space next-char) (read-char line-stream))
|
((char= #\Space next-char) (read-char line-stream))
|
||||||
((char= #\; next-char) ;; and not in string
|
((char= #\; next-char) ;; and not in string
|
||||||
(finish))
|
(finish))
|
||||||
@@ -55,113 +50,142 @@
|
|||||||
(next-iteration)))
|
(next-iteration)))
|
||||||
(for next-sym in-stream line-stream
|
(for next-sym in-stream line-stream
|
||||||
using #'read-preserving-whitespace)
|
using #'read-preserving-whitespace)
|
||||||
(multiple-value-bind (token err)
|
(collect (make-token next-sym line-num col) into tokens)
|
||||||
(make-token next-sym line-num col)
|
(incf col (length (princ-to-string next-sym)))
|
||||||
(collect token into tokens)
|
(finally (return tokens)))))
|
||||||
(when err ;; skip line on error and continue lexing
|
|
||||||
(setf has-err t)
|
|
||||||
(finish))
|
|
||||||
(incf col (length (princ-to-string next-sym))))
|
|
||||||
(finally (return (values tokens has-err))))))
|
|
||||||
|
|
||||||
(defun lex-file (file-name &optional report-errors)
|
(defun lex-stream (str)
|
||||||
(let ((has-error nil))
|
(iter (for line = (read-line str nil nil))
|
||||||
(values
|
(until (null line))
|
||||||
|
(for line-num from 1)
|
||||||
|
(appending (lex-line line line-num))))
|
||||||
|
|
||||||
|
(defun lex-file (file-name)
|
||||||
(with-open-file (str file-name :external-format :utf-8)
|
(with-open-file (str file-name :external-format :utf-8)
|
||||||
(iter outer
|
(lex-stream str)))
|
||||||
(for line = (read-line str nil nil))
|
|
||||||
(until (null line))
|
(defun lex-string (string)
|
||||||
(for line-num from 1)
|
(lex-stream (make-string-input-stream string)))
|
||||||
(multiple-value-bind (tokens has-err)
|
|
||||||
(lex-line line line-num)
|
|
||||||
(when has-err
|
|
||||||
(setf has-error t)
|
|
||||||
(when report-errors
|
|
||||||
(let ((err-token (find-if (lambda (tok) (find :error tok))
|
|
||||||
tokens)))
|
|
||||||
(format t "~5@a ~a~%"
|
|
||||||
(format nil "~a:" (getf (cdr err-token) :line))
|
|
||||||
line)
|
|
||||||
(format t " ~a^~%"
|
|
||||||
(make-string (getf (cdr err-token) :col)
|
|
||||||
:initial-element #\Space)))))
|
|
||||||
(appending tokens))))
|
|
||||||
has-error)))
|
|
||||||
|
|
||||||
(defun lex-string (string &optional report-errors)
|
|
||||||
(let ((has-error nil))
|
|
||||||
(values
|
|
||||||
(let ((str (make-string-input-stream string)))
|
|
||||||
(iter outer
|
|
||||||
(for line = (read-line str nil nil))
|
|
||||||
(until (null line))
|
|
||||||
(for line-num from 1)
|
|
||||||
(multiple-value-bind (tokens has-err)
|
|
||||||
(lex-line line line-num)
|
|
||||||
(when has-err
|
|
||||||
(setf has-error t)
|
|
||||||
(when report-errors
|
|
||||||
(format t "~a~%" line)
|
|
||||||
(let ((err-token (find-if (lambda (tok) (find :error tok))
|
|
||||||
tokens)))
|
|
||||||
(format t "~a^"
|
|
||||||
(make-string (getf (cdr err-token) :col)
|
|
||||||
:initial-element #\Space)))))
|
|
||||||
(appending tokens))))
|
|
||||||
has-error)))
|
|
||||||
|
|
||||||
;;; PARSER
|
;;; PARSER
|
||||||
(defun parse-tokens (tokens)
|
(defmacro add-op (token parser)
|
||||||
(iter (with ops = (make-array (length tokens) :fill-pointer 0
|
`(progn (vector-push-extend ,token (ops ,parser))
|
||||||
|
(incf (index ,parser))))
|
||||||
|
|
||||||
|
(defparameter *makro-defs* (make-hash-table))
|
||||||
|
|
||||||
|
(defclass parser ()
|
||||||
|
((if-stack :initform ()
|
||||||
|
:accessor if-stack)
|
||||||
|
(ops :accessor ops)
|
||||||
|
(tokens :initarg :tokens
|
||||||
|
:accessor tokens)
|
||||||
|
(index :initform 0
|
||||||
|
:accessor index)))
|
||||||
|
|
||||||
|
(defun make-parser (tokens)
|
||||||
|
(let ((parser (make-instance 'parser :tokens tokens)))
|
||||||
|
(setf (ops parser) (make-array (length tokens) :fill-pointer 0
|
||||||
:adjustable t))
|
:adjustable t))
|
||||||
(with stack = ())
|
parser))
|
||||||
(for i from 0)
|
|
||||||
(for token in tokens)
|
(defmethod peek-token ((parser parser))
|
||||||
(let ((op (token-op token))
|
(car (tokens parser)))
|
||||||
(op-type (getf (cdr token) :type)))
|
|
||||||
(cond ((eq :number op-type)
|
(defmethod read-token ((parser parser))
|
||||||
(vector-push-extend `(:push-int ,op) ops))
|
(pop (tokens parser)))
|
||||||
((eq :string op-type)
|
|
||||||
(vector-push-extend `(:push-str ,(length op) ,i ,op)
|
(defmethod parse-token ((parser parser) (type (eql :number)))
|
||||||
ops))
|
(add-op `(:push-int ,(car (read-token parser))) parser))
|
||||||
((string= :ise op)
|
|
||||||
(push (list :ise i) stack)
|
(defmethod parse-token ((parser parser) (type (eql :string)))
|
||||||
(vector-push-extend (list :ise nil) ops))
|
(let ((token (read-token parser)))
|
||||||
((string= :yoksa op)
|
(add-op `(:push-str ,(length (car token))
|
||||||
(let ((top (pop stack)))
|
,(index parser)
|
||||||
(assert (string= :ise (car top)))
|
,(car token))
|
||||||
(setf (second (aref ops (cadr top))) i)
|
parser)))
|
||||||
(push (list :yoksa i) stack)
|
|
||||||
(vector-push-extend (list :yoksa nil i) ops)))
|
(defmethod parse-token ((parser parser) (type (eql :identifier)))
|
||||||
((string= :yap op)
|
(let ((token (read-token parser)))
|
||||||
(let ((top (pop stack)))
|
(parse-op parser token (car token))))
|
||||||
|
|
||||||
|
(defmethod parse-token ((parser parser) (type (eql :unknown)))
|
||||||
|
(let* ((token (read-token parser))
|
||||||
|
(makrodef (gethash (car token) *makro-defs*)))
|
||||||
|
(if (not (null makrodef))
|
||||||
|
;; (parser-parse-tokens parser makrodef)
|
||||||
|
(setf (tokens parser) (append makrodef (tokens parser)))
|
||||||
|
(error "parse-token: token has unknown identifier: ~a"
|
||||||
|
(read-token parser)))))
|
||||||
|
|
||||||
|
;; (defmethod parser-parse-tokens ((parser parser) tokens)
|
||||||
|
;; (iter (for makro-op in-vector)
|
||||||
|
;; (add-op makro-op ops))
|
||||||
|
;; ())
|
||||||
|
|
||||||
|
(defmethod parse-op ((parser parser) token (type (eql :ise)))
|
||||||
|
(push (list :ise (index parser)) (if-stack parser))
|
||||||
|
(add-op (list :ise nil) parser))
|
||||||
|
|
||||||
|
(defmethod parse-op ((parser parser) token (type (eql :yoksa)))
|
||||||
|
(let ((top (pop (if-stack parser))))
|
||||||
|
(assert (and (string= :ise (car top))
|
||||||
|
(string= :ise (car (aref (ops parser) (cadr top))))))
|
||||||
|
(setf (second (aref (ops parser) (cadr top))) (index parser))
|
||||||
|
(push (list :yoksa (index parser)) (if-stack parser))
|
||||||
|
(add-op (list :yoksa nil (index parser)) parser)))
|
||||||
|
|
||||||
|
(defmethod parse-op ((parser parser) token (type (eql :yap)))
|
||||||
|
(let ((top (pop (if-stack parser))))
|
||||||
|
(unless (and (find (car top) (list :yoksa :ise :iken))
|
||||||
|
(find (car (aref (ops parser) (cadr top)))
|
||||||
|
(list :yoksa :ise :iken)))
|
||||||
|
(error "yap cannot close ~a" (aref (ops parser) (cadr top))))
|
||||||
(cond ((find (car top) (list :yoksa :ise))
|
(cond ((find (car top) (list :yoksa :ise))
|
||||||
(setf (second (aref ops (cadr top))) i)
|
(setf (second (aref (ops parser) (cadr top))) (index parser))
|
||||||
(vector-push-extend (list :yap i) ops))
|
(add-op (list :yap (index parser)) parser))
|
||||||
((string= :iken (car top))
|
((string= :iken (car top))
|
||||||
(setf (second (aref ops (cadr top))) i)
|
(setf (second (aref (ops parser) (cadr top))) (index parser))
|
||||||
(vector-push-extend (list :yap i (third top)) ops))
|
(add-op (list :yap (index parser) (third top)) parser))
|
||||||
(t (error "yap cannot reference: ~a" (car top))))))
|
(t (error "yap cannot reference: ~a" (car top))))))
|
||||||
((string= :döngü op)
|
|
||||||
(push (list :döngü i) stack)
|
(defmethod parse-op ((parser parser) token (type (eql :döngü)))
|
||||||
(vector-push-extend (list :döngü i) ops))
|
(push (list :döngü (index parser)) (if-stack parser))
|
||||||
((string= :iken op)
|
(add-op (list :döngü (index parser)) parser))
|
||||||
(let ((top (pop stack)))
|
|
||||||
|
(defmethod parse-op ((parser parser) token (type (eql :iken)))
|
||||||
|
(let ((top (pop (if-stack parser))))
|
||||||
(assert (string= :döngü (car top)))
|
(assert (string= :döngü (car top)))
|
||||||
(push (list :iken i (cadr top)) stack)
|
(push (list :iken (index parser) (cadr top)) (if-stack parser))
|
||||||
(vector-push-extend (list :iken nil) ops)))
|
(add-op (list :iken nil) parser)))
|
||||||
((search "syscall" (string-downcase (string op)))
|
|
||||||
(let ((syscall-num (parse-integer (subseq (string op) 8))))
|
(defmethod parse-op ((parser parser) token (type (eql :makro)))
|
||||||
(vector-push-extend (list :syscall syscall-num) ops)))
|
;; makro name must be undefined before
|
||||||
(t (vector-push-extend (list op) ops))))
|
(let ((makro-name-tok (read-token parser)))
|
||||||
(finally (return ops))))
|
(assert (eq :unknown (getf (cdr makro-name-tok) :type)))
|
||||||
|
(setf (gethash (car makro-name-tok) *makro-defs*)
|
||||||
|
(do ((tok (read-token parser)
|
||||||
|
(read-token parser))
|
||||||
|
(makrodef ()))
|
||||||
|
((eq :son (car tok)) (reverse makrodef))
|
||||||
|
(push tok makrodef)))))
|
||||||
|
|
||||||
|
(defmethod parse-op ((parser parser) token type)
|
||||||
|
(cond ((search "syscall" (string-downcase (string (car token))))
|
||||||
|
(let ((syscall-num (parse-integer (subseq (string (car token)) 8))))
|
||||||
|
(add-op (list :syscall syscall-num) parser)))
|
||||||
|
(t (add-op (list type) parser))))
|
||||||
|
|
||||||
|
(defun parse-tokens (tokens)
|
||||||
|
(let ((parser (make-parser tokens)))
|
||||||
|
(iter (while (not (null (tokens parser))))
|
||||||
|
(parse-token parser (getf (cdr (peek-token parser)) :type)))
|
||||||
|
(ops parser)))
|
||||||
|
|
||||||
(defun make-program (file-name)
|
(defun make-program (file-name)
|
||||||
(multiple-value-bind (tokens has-error)
|
(parse-tokens (lex-file file-name)))
|
||||||
(lex-file file-name t)
|
|
||||||
(when has-error
|
|
||||||
(error "Can't generate program due to error during lexing"))
|
|
||||||
(parse-tokens tokens)))
|
|
||||||
|
|
||||||
;;; COMPILER
|
;;; COMPILER
|
||||||
;;(defgeneric write-program (target program stream))
|
;;(defgeneric write-program (target program stream))
|
||||||
|
|||||||
@@ -16,13 +16,6 @@
|
|||||||
(:string new-file)
|
(:string new-file)
|
||||||
(:file (pathname new-file)))))
|
(:file (pathname new-file)))))
|
||||||
|
|
||||||
(defun lex-stream (str)
|
|
||||||
(iter outer
|
|
||||||
(for line = (read-line str nil nil))
|
|
||||||
(until (null line))
|
|
||||||
(for line-num from 1)
|
|
||||||
(appending (lex-line line line-num))))
|
|
||||||
|
|
||||||
(defun read-form-comment (str)
|
(defun read-form-comment (str)
|
||||||
(read-from-string
|
(read-from-string
|
||||||
(format nil "~{~a~^~%~}"
|
(format nil "~{~a~^~%~}"
|
||||||
|
|||||||
Reference in New Issue
Block a user