⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lisp.pl

📁 LISP interpreter implemented with PERL.
💻 PL
字号:
#!/usr/bin/perl## Lisp.pl: A tiny Lisp interpreter using Perl.## This file and all associated files and documentation:#       Copyright (C) 2000 Ali Onur Cinar <root@zdo.com>## Latest version can be downloaded from:##   ftp://ftp.cpan.org/pub/CPAN/authors/id/A/AO/AOCINAR/elmtag*#   http://www.zdo.com## This program is free software; you can redistribute it and/or# modify it under the terms of the GNU General Public License# as published by the Free Software Foundation; either version 2# of the License, or (at your option) any later version. And also# please DO NOT REMOVE my name, and give me a CREDIT when you use# whole or a part of this program in an other program.## This program is distributed in the hope that it will be useful,# but WITHOUT ANY WARRANTY; without even the implied warranty of# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the# GNU General Public License for more details.## You should have received a copy of the GNU General Public License# along with this program; if not, write to the Free Software# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.####### GLOBALS###	$DEBUG = 0;	# 0=off 1=on###### SYMBOL TABLE###	%SYMBOLS = (		x	=> 3,		y	=> 2,		z	=> 4,		list1	=> "(3 2 4)",		list2	=> "(5 6)",		list3	=> "nil"	);###### MAIN ### FUNCTION######	print "** Lisp Interpreter v1.0.0\n";	print "**\n";	print "**  Commands:\n";	print "**   > debug       turn debug option on/off\n";	print "**   > quit        exit from command line\n";	print "**\n";	print "**  Available Tests:\n";	print "**   1. (+ 3 4 5 6 (* 2 4 (- 5) (+ 3)) (- (- 3 5)) (* 4))\n";	print "**   2. (or (and (= 3 5) (= 3 3)) (if 7 3 2) nil)\n";	print "**   3. (cons (list 5 3 6) (list 'ga 'ha (first '(7 4 (list 2 'ha)))))\n";	print "**   4. (apply #'+ (rest (list (list 3 4 5) 6 (funcall #'- 2 3))))\n";	print "**   5. (equal (list 3 5) (list 3 (- 7 2)))\n";	print "**   6. (list list1 (apply #'+ list1) y)\n";	print "**   7. (equal (cons list1 list2) (cons (list x y z) (cons (first list2) (rest list2))))\n";	print "**   8. (first (rest (list 1 (+ 2 3 (* 4 5)) 6 7 8)))\n";	print "**   9. (apply #'or ((funcall #'and 1 0) 1))\n";	print "**\n\n";	print "> ";	# get users input from the command line	# and then evaluate the given LISP code	while (<STDIN>)	{	  # if user wants to quit then exit	  if ($_ =~ /[Qq][Uu][Ii][Tt]/) {	    print "\nGoodbye!\n\n";	    exit 0;	  }	  # if user wants to turn on/off debug option	  if ($_ =~ /[Dd][Ee][Bb][Uu][Gg]/) {	    $DEBUG = ($DEBUG) ? 0 : 1;            print "\nDebug is ".(($DEBUG)?'on':'off')."\n";	  }	  else {	    # evaluate the given LISP code	    Evaluate($_);	  }	  # print prompt	  print "\n> ";	}###### LISP INTERPRETER### FUNCTION###### @param	: string -> lisp code### @return	: n/a### @output	: stdout -> result###		  stderr -> errors###sub Evaluate ($){	# INPUTED LIST CODE	$LISP = shift @_;	# CLEAN SPACES FROM THE BEGINNING OF CODE	$LISP =~ s/^ +//;	# GLOBALS	$LEVEL = 0;		# Holds the numbers of levels	@OPER  = undef;		# Stack for Operators	@VALUES= undef;		# Stack for Value lists	$next_is_oper=0;	# Set if next expected char				# should be an operator	# Go through the LISP expression and evaluate	for ($i=0; $i<length($LISP); $i++) {	    #read next available character	    $char = substr($LISP,$i,1);	    #if it is the first character and	    #it is not ( then throw a syntax error	    if (($i==0) && ($char ne "(")) {	      print "\n! SYNTAX ERROR ON COLUMN 0\n";	      return;	    }	    # if the expected character is an	    # operator then identify the operator	    # else throw a syntax error 	    if ($next_is_oper == 1) {	      if ($char eq "+") {	# If operator is +                push(@OPER, "+");	      }	      elsif ($char eq "-") {	# If operator is - 		push(@OPER, "-");	      }	      elsif ($char eq "*") {	# If operator is *		push(@OPER, "*");	      }	      elsif ($char eq "=") {	# If operator is =		push(@OPER, "=");	      }	      elsif ($char eq "a") {	# If operator is and	        $char = substr($LISP,$i+1,1);	        if ($char eq "n") {			  push(@OPER, "and");		  $i+=2;                } elsif ($char eq "p") {# If operator is apply		  push(@OPER, "apply");		  $i+=4;		} else {		  print "\n! UNKNOWN OPERATOR CALL \n";		  return;		}	      }	      elsif ($char eq "o") {	# If operator is or		push(@OPER, "or");		$i++;	      }	      elsif ($char eq "i") {	# If operator is if 		push(@OPER, "if");		$i++;	      }	      elsif ($char eq "l") {	# If operator is list	        $char = substr($LISP,$i+1,1);	        if ($char eq "i") {			  push(@OPER, "list");		  $i+=3;		} elsif ($char eq "a") {# If operator is lambda		  push(@OPER, "lambda");		  $i+=5;		} else {		  print "\n! UNKNOWN OPERATOR CALL \n";		  return;		}	      }	      elsif ($char eq "e") {	# If operator is equal		push(@OPER, "=");		$i+=4;	      }	      elsif ($char eq "f") {	# If operator is first	        $char = substr($LISP,$i+1,1);	        if ($char eq "i") {			  push(@OPER, "first");		  $i+=4;                } elsif ($char eq "u") {# If operator is funcall		  push(@OPER, "funcall");		  $i+=6;		} else {		  print "\n! UNKNOWN OPERATOR CALL \n";		  return;		}	      }	      elsif ($char eq "r") {	# If operator is rest		push(@OPER, "rest");		$i+=3;	      }	      elsif ($char eq "c") {	# If operator is cons		push(@OPER, "cons");		$i+=3;	      }	      else {			# probably a list		push(@OPER, "list");		$i--;	      }	      $next_is_oper=0;		# reset it	    }	    # If the next character is not a space	    # then check if it is ( or ) or a value	    elsif (($char ne " ") && ($char ne "'") && ($next_is_oper == 0)) {	      if ($char eq "(") {	# If it is ( then		$LEVEL++;		# start a new level		$next_is_oper=1;	# next character should be 					# an operator		push (@VALUES, "");	# insert a blank value list	      }	      elsif ($char eq ")") {	# If it is ) then					# finish the current level					# And evaluate the expression		# DEBUG 		(print "DEBUG: level: $LEVEL  operator: ".$OPER[$LEVEL]			." values: {" .$VALUES[$LEVEL]) if ($DEBUG);		# DEBUG 		# Put the values inside a list structure			@numbers = split (/,/,$VALUES[$LEVEL]);		$VALUES[$LEVEL] = ''; # free some memory 		# Shift the first element of list since it 		# will be always a space 		shift(@numbers);		# Check symbol lookup table for pre-defined		# symbol values		for ($k=0;$k<=$#numbers;$k++) {		  $numbers[$k] = symbolLookup($numbers[$k]);		}		# set eval = the first value in list		$eval = $numbers[0];		# check for apply		if ($OPER[$LEVEL] eq "apply") {		  $OPER[$LEVEL] = substr ($numbers[0], 2,length($numbers[0])-2);		  @numbers = split(/ /, substr($numbers[1],1,length($numbers[1])-2));		  $eval = $numbers[0];		}		# check for funcall		if ($OPER[$LEVEL] eq "funcall") { 		  $OPER[$LEVEL] = substr ($numbers[0], 2,length($numbers[0])-2);		  $eval = $numbers[1];		  shift @numbers;		}		if ($OPER[$LEVEL] eq "if") {		  # check for condition, if numbers[0] is not equal to "nil"		  # then return numbers[2] else return numbers[1]		  if ($numbers[0] == 0) {		    $eval = $numbers[2];		  } else {		    $eval = $numbers[1];		  }		}		elsif ($OPER[$LEVEL] eq "lambda") {		  foreach (@numbers) {		    print "=> $_\n";		  }		}		elsif ($OPER[$LEVEL] eq "list") {		  $eval = '('.join (' ',@numbers).')';		}		elsif ($OPER[$LEVEL] eq "cons") {		  $eval = '('.join (' ',@numbers).')';		}		elsif ($OPER[$LEVEL] eq "first") {		  @tmp = splitIt(substr($numbers[0],1,length($numbers[0])-2));		  $eval = $tmp[0];		}		elsif ($OPER[$LEVEL] eq "rest") {		  @tmp = splitIt(substr($numbers[0],1,length($numbers[0])-2));		  shift @tmp;		  $eval = '('.join (' ',@tmp).')';		}		elsif ($#numbers == 0) { # if it is like (- 5)					 # then it means -5		    $eval =~ s/ //;		    # ($eval = $eval * $eval) if ($OPER[$LEVEL] eq "*"); # 5^2 case		    ($eval = -1 * $eval)    if ($OPER[$LEVEL] eq "-"); # -5 case		}		else {		  # do the necessary steps if it's an operation		  for ($j=1;$j<=$#numbers;$j++) {		    ($eval *= int($numbers[$j])) if ($OPER[$LEVEL] eq "*"); # oper *		    ($eval += int($numbers[$j])) if ($OPER[$LEVEL] eq "+"); # oper +		    ($eval -= int($numbers[$j])) if ($OPER[$LEVEL] eq "-"); # oper -		    ($eval = (($eval == int($numbers[$j])) ? "t" : "nil"))				if ($OPER[$LEVEL] eq "=");	       # oper =		    ($eval = (((int($numbers[$j])==0) || ($numbers[$j] eq "nil")) ? "nil" : $eval))				if ($OPER[$LEVEL] eq "and");	       # oper and		    ($eval = (((int($numbers[$j])==0) || ($numbers[$j] eq "nil")) ? $eval : int($numbers[$j])))				if ($OPER[$LEVEL] eq "or");	       # oper or		  }		}		# if it is a logic operation (= and or)		# then just return 0 for 0 and 1 for the rest		#if (($OPER[$LEVEL] eq "=")		#    || ($OPER[$LEVEL] eq "and")		#    || ($OPER[$LEVEL] eq "or")) {		#		#  $eval = ($eval == 0) ? 0 : 1;		#}		# DEBUG 		(print "} eval: $eval\n\n") if ($DEBUG);		# DEBUG 		# close this level		$LEVEL--;		# check for completation of interpretation		if ($LEVEL == 0) {	# it this was the last level		   print "= Result: $eval\n"; # report the value		} else {		# else add the value to the					# end of parent level		  $VALUES[$LEVEL] .= ",$eval";		}		pop (@OPER);		pop (@VALUES);	      }	      else {			# Parse the number		$value='';		# Clean the value first		# Parse the whole number terminated by a space		# or by a ) character		while ( ($i<length($LISP)) && ($char ne " ") && ($char ne ")") ) {		   $value .= $char;		   $i++;	    	   $char = substr($LISP,$i,1);		}		# if it is terminated by a space of ) then		# decrease the cursor so we wont skip		# a ) sign		if (($char eq " ") || ($char eq ")")) {		   $i--;		}		# if the value is "nil" then translate it to 0		# if the value is "t" then translate it to 1		#($value = 0) if ($value eq "nil");		#($value = 1) if ($value eq "t");		# add the current value to the end of the		# value list for this level		$VALUES[$LEVEL] .= ",$value";	      }            } else {			# catch spaces	      # DEBUG 	      # print "CC: $char ($next_is_oper)\n";	      # DEBUG 	    }	}}###### SPLITER### FUNCTION###### @param	: string -> list string### @return	: array### @output	: n/a###sub splitIt ($){ 	  # get input 	  local $str = shift @_;	  $str =~ s/\ \ +/ /g;	  # vars	  local @values = undef;	  local $paran = 0;	  local $index = 0;	  local $i = 0;		  push (@values, "");	 	  for ($i=0; $i<length($str); $i++) {	    $char = substr($str,$i,1);		    if ($char eq "(") {	      $values[$index].='(';	      $paran++;	    }	    elsif ($char eq ")") {	      $values[$index].=')';	      $paran--;	    }	    elsif (($char eq " ") && ($paran == 0)) {	        $index++;	        push (@values,"");	    }	    else {	      $values[$index].=$char;	    }	  }		  # return the array	  return @values;}###### SYMBOL TABLE LOOKUP### FUNCTION###### @param	: string -> symbol name### @return	: symbol value### @output	: n/a###sub symbolLookup ($){    local $name = shift @_;   return ($SYMBOLS{$name} eq "") ? $name : $SYMBOLS{$name};}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -