LOR-contest/Counter-Lisp

Материал из LORWiki
Перейти к навигацииПерейти к поиску

Программа писана больше для личного употребления, поэтому у нее практически нет интерфейса. Файл для подсчета захардкоден в самом конце, в виде пути к файлу типа «advworld.lisp».

Для разбора различных языков используются макросы типа make-lisp-classifier, использование конкретного макроса тоже хардкодидся в последней страке.

Примечание: текст слегка не влез по ширине, поэтому советую скопипастить его для изучения и/или использования. Если кто-нибудь отформатирует, буду очень благодарен --Евгений Косенко 05-Jul-2008 17:25 MSD

(require 'lexer)
(in-package lexer)

(defun lex-class (class-def)
  (mapcar 
	#'(lambda (regex) `(,regex (return (values ,(car class-def) %0))))
	(cdr class-def)))

(defmacro defclassifier (name class-list skip-list)
  `(deflexer ,name
	  :flex-compatible 
	  ,@(mapcan #'lex-class class-list)
	  ,@(mapcar #'list skip-list)))

(defclassifier make-haskell-classifier
  ((:keyword
	 .("," "\\." "\\|" "=" "==" "<=" ">" "_" "\\\\" "`" "&&" "\\+\\+" "<\\-" "\\->" "!" "@" "\\$" "\\+" "\\-"
		":" "::" "\\[" "\\]" "\\(" "\\)" "\\{" "\\}" "case" "data" "do" "deriving" "else" "hiding" "if" "import" 
 		"let" "module" "of" "otherwise" "then" "where"))

	(:meanword
	 .("\"[^\"]*\"" "\'[^\']\'" "(-)?[0-9]+" "[A-Za-z_][A-Za-z_]*(')?")))

	;skipword
  ("[:space:]+"))

(defclassifier make-ocaml-classifier
  ((:keyword
	 .("!=" "%" "&" "&&" "," ":" "::" ";" ";;" "<" "<\\-" "=" ">" ">=" "@" "Array"
		"List" "Queue" "\\(" "\\)" "\\*" "\\+" "\\-" "\\->" "\\." "\\[" "\\]" "\\{"
		"\\|" "\\|\\|" "\\}" "assoc" "create" "do" "done" "else" "flush" "for" "fun"
		"function" "if" "in" "iter" "length" "let" "loop" "make_matrix" "map" "not"
		"pop" "push" "raise" "then" "to" "true" "try" "with" "filter" "make" "init"
		"string" "String" "index" "ignore" "rec" "open" "val" "bool" "int" "array"
		"when" "copy"))

	(:meanword
	 .("\"[^\"]*\"" "'[^']*'" "(-)?[0-9]+" "[A-Za-z_][A-Za-z_]*(')?")))

	;skipword
  ("//.*$" "[:space:]+"))

(defclassifier make-c++-classifier
  ((:keyword
	 .("!=" "#include" "%" "&" "," ":" "::" ";" "<" "<<" "=" ">" ">=" ">>" "\\("
		"\\)" "\\*" "\\+" "\\+\\+" "\\->" "\\." "\\[" "\\]" "\\{" "\\|\\|" "\\}"
		"bool" "class" "const" "for" "if" "int" "namespace" "operator" "return" "std"
		"struct" "try" "typedef" "using" "void"))

	(:meanword
	 .("\"[^\"]*\"" "(-)?[0-9]+" "[A-Za-z_][A-Za-z_]*")))

  ;skipword
  ("//.*$" "[:space:]+"))

(defclassifier make-python-classifier
  ((:keyword 
	 .("\\|" "\\&" "\\\\" "\\+=" "==" "\\-" "\\{" "\\}" "!=" "%" "," ":" "<" "=" ">" ">=" "\\(" "\\)" "\\*" "\\+" "\\." 
		"\\[" "\\]"
		"__class__" "__init__" "__name__" "__unicode__" "append" "class" "cond" "def"
		"dict" "except" "for" "if" "import" "in" "join" "lambda" "len" "list" "print"
		"return" "setattr" "try" "unicode" "yield" "raise" "or" "pass" "xrange" "__str__" "break" 
		"None" "is" "while" "has_key" "from"))

	(:meanword
	 .("`[^']+`" "\"[^\"]*\"" "(-)?[0-9]+" "[A-Za-z_][A-Za-z_]*" "u?'[^']*'")))

  ;skipword	
  ("#.*$" "[:space:]+"))

(defclassifier make-lisp-classifier
  ((:keyword 
	 .("&body" "#\\." "\\-" "#[cC]" "1-" "\\." "#'" "%" "&key" "&optional" "'" "," ",@" "/" "1\\+" ":" ":test" "<" "<>" "="
		">" ">=" "\\(" "\\)" "\\*" "\\+" "`" "and" "break" "caar" "cond" "defun" "eq"
		"equal" "gethash" "if" "in-package" "lambda" "length" "list" "make-hash-table"
		"make-instance" "not" "print" "progn" "push" "setf" "setq" "slot-value"
		"string=" "t" "terpri" "append" "reverse" "cadr" "min" "reduce" "assoc" "throw"
		"mapcan" "remove-if" "defmacro" "remove" "pairlis" "defconstant" "across" "read-line" "listen"
		"while" "upfrom" "with-open-file" "finally" "format" "princ" "complex" "let" "do" "to" "from" "for"
		"loop" "eql" "member" "null" "or" "imagpart" "realpart" "cons" "car" "cdr" "nil" "defvar"
		"eval" "eval" "mapcar" "&rest" "read" "with-open-stream" "return" "unless" "read-from-string"
		"string" "concatenate" "remove-dublicates" "#c" ":conc-name" "defctruct" "max" "case" "require"
		"initially" "remove-duplicates" "quote" ":count" "when" "upto" "\\(\\)" "count" "numberp"))

	(:meanword
	 .("#\\\\." "\"[^\"]*\"" "(\\-)?[0-9]+" "[A-Za-z][A-Za-z0-9\\-\\+!]*" "[\\[]" "[\\]]")))

  ;skipword	
  (";.*$" "[:space:]+"))

(defun collect-stats (token-stream keywords meanwords trace-lex)
	 (multiple-value-bind 
	  (class value) (funcall token-stream)
	  (cond ((eq class nil))
			  (t (cond ((eq class :keyword)
							(setf (gethash value keywords) (1+ (gethash value keywords 0))))
						  ((eq class :meanword)
							(setf (gethash value meanwords) (1+ (gethash value meanwords 0))))
						  (t (throw :invalid-class (values nil class))))
				  (cond
					(trace-lex
					 (prin1 class)
					 (prin1 " ")
					 (prin1 value)
					 (terpri)))
				  (collect-stats token-stream keywords meanwords trace-lex)))))

(defun hash-sum (hash)
  (let ((sum 0)) 
	 (maphash #'(lambda (k v) (declare (ignore k)) (incf sum v)) hash)
	 sum))

(defun hash-keys (hash)
  (let ((keys ()))
	 (maphash #'(lambda (k v) (declare (ignore v)) (push k keys)) hash) keys))

(defun % (part total)
  (values (round (float (* 100 (/ part total))))))

(defun lo-stats (token-stream trace-lex show-classes)
  	 (let 
		  ((keywords (make-hash-table :test #'equal)) (meanwords (make-hash-table :test #'equal)))
		(collect-stats token-stream keywords meanwords trace-lex)
		(cond
		 (show-classes
		  (princ "Keywords: ")
		  (prin1 (hash-keys keywords))
		  (terpri)
		  (princ "Meanwords: ")
		  (prin1 (hash-keys meanwords))
		  (terpri)))
		(values
		 (hash-sum keywords)
		 (hash-sum meanwords)
		 (hash-table-count keywords)
		 (hash-table-count meanwords))))

(defun hi-stats (token-stream &key (trace-lex nil) (show-classes nil))
  (multiple-value-bind 
	(keyword-length meaning-length keyword-thesaurus meaning-thesaurus)
	(lo-stats token-stream trace-lex show-classes)
	(let ((total-length (+ keyword-length meaning-length))
			(total-thesaurus (+ keyword-thesaurus meaning-thesaurus)))
	  (list
		(cons "Total length" total-length)
		(cons "Meaning length" meaning-length)
		(cons "Total thesaurus" total-thesaurus)
		(cons "Meaning thesaurus" meaning-thesaurus)
		(cons "Total saturation (%)" (% meaning-length total-length))
		(cons "Thesaurus saturation (%)" (% meaning-thesaurus total-thesaurus))
		(cons "Total expressiveness (%)" (% total-thesaurus total-length))
		(cons "Meaning expressiveness (%)" 
				(if (> meaning-length 0) (% meaning-thesaurus meaning-length) 0))))))

(defun print-result (result-table)
  (mapcar
	 #'(lambda (pair) (format t "~A~50T~7D~%" (car pair) (cdr pair)))
	 result-table))

(defun read-content (file-name)
  (with-open-file 
	(s file-name)
	(let
		 ((data (make-string (file-length s)))) 
	  (read-sequence data s) data)))

(print-result (hi-stats (make-haskell-classifier (read-content "advworld.lisp"))))