Guest User

https://code.likeagirl.io/how-to-write-a-lisp-interpreter-under-150-lines-of-code-2c0c361be621

a guest
Jun 11th, 2024
190
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 4.63 KB | None | 0 0
  1. // PARSER
  2.  
  3. import java.io.IOException;
  4. import java.io.PushbackReader;
  5. import java.io.StringReader;
  6.  
  7. public class Parser {
  8.  
  9.   public AST parse(String str) throws IOException {
  10.     try (PushbackReader reader = new PushbackReader(new StringReader(str))) {
  11.       AST ast = parse(reader);
  12.       String rest = peek(reader);
  13.       if (rest != null)
  14.         throw new RuntimeException("Unexpected tokens: " + rest);
  15.       return ast;
  16.     }
  17.   }
  18.  
  19.   private AST parse(PushbackReader reader) throws IOException {
  20.     String token = nextToken(reader);
  21.     if (")".equals(token) || "".equals(token))
  22.       throw new RuntimeException("Unbalanced parenthesis");
  23.     if ("(".equals(token)) {
  24.       AST list = new AST(token);
  25.       while (!")".equals(peek(reader)))
  26.         list.add(parse(reader));
  27.       nextToken(reader); // skip )
  28.       return list;
  29.     }
  30.     return new AST(token); // atom
  31.   }
  32.  
  33.   private String nextToken(PushbackReader reader) throws IOException {
  34.     String chr = peek(reader);
  35.     return "(".equals(chr) || ")".equals(chr)
  36.             ? String.valueOf((char) reader.read())
  37.             : nextAtom(reader);
  38.   }
  39.  
  40.   private String nextAtom(PushbackReader reader) throws IOException {
  41.     StringBuilder buffer = new StringBuilder();
  42.     int chr = reader.read();
  43.     while (chr != -1 && !Character.isWhitespace(chr) && ')' != chr) {
  44.       buffer.append((char)chr);
  45.       chr = reader.read();
  46.     }
  47.     if (chr == ')')
  48.       reader.unread(')');
  49.     return buffer.toString();
  50.   }
  51.  
  52.   private String peek(PushbackReader reader) throws IOException {
  53.     int chr = reader.read();
  54.     while (chr != -1 && Character.isWhitespace(chr))
  55.       chr = reader.read();
  56.     if (chr == -1)
  57.       return null;
  58.     reader.unread(chr);
  59.     return String.valueOf((char) chr);
  60.   }
  61. }
  62.  
  63. // AST
  64.  
  65. import java.util.ArrayList;
  66. import java.util.List;
  67.  
  68. public class AST {
  69.   private final List<AST> children = new ArrayList<>();
  70.   private final String token;
  71.  
  72.   public AST(String token) {
  73.     this.token = token;
  74.   }
  75.  
  76.   public void add(AST child) {
  77.     children.add(child);
  78.   }
  79.  
  80.   public String token() {
  81.     return token;
  82.   }
  83.  
  84.   public Double numValue() {
  85.     return Double.parseDouble(token);
  86.   }
  87.  
  88.   public boolean boolValue() {
  89.     System.out.println("Token: " + token);
  90.     return Boolean.parseBoolean(token);
  91.   }
  92.  
  93.   public boolean isAtom() {
  94.     return children.isEmpty();
  95.   }
  96.  
  97.   public AST head() {
  98.     return children.get(0);
  99.   }
  100.  
  101.   public List<AST> tail() {
  102.     return children.subList(1, children.size());
  103.   }
  104.  
  105.   @Override
  106.   public String toString() {
  107.     return isAtom() ? token : children.toString();
  108.   }
  109. }
  110.  
  111. // INTERPRETER
  112.  
  113. import java.util.HashMap;
  114. import java.util.List;
  115. import java.util.Map;
  116. import static java.util.stream.Collectors.toList;
  117.  
  118. public class Interpreter {
  119.   private final Map<String, Func> functions = new HashMap<>();
  120.   private final Map<String, SpecialForm> specialForms = new HashMap<>();
  121.  
  122.   public interface Func {
  123.     Object call(List<Object> parameters);
  124.   }
  125.  
  126.   public interface SpecialForm {
  127.     Object call(List<AST> parameters);
  128.   }
  129.  
  130.   public Interpreter() {
  131.     addFunction("=", args -> args.get(0).equals(args.get(1)));
  132.     addFunction("+", args -> (Double) args.get(0) + (Double) args.get(1));
  133.     addFunction("-", args -> (Double) args.get(0) - (Double) args.get(1));
  134.     addFunction("*", args -> (Double) args.get(0) * (Double) args.get(1));
  135.     addFunction("/", args -> (Double) args.get(0) / (Double) args.get(1));
  136.     addFunction("not", args -> !(boolean) args.get(0));
  137.     addSpecialForm("or", args -> args.stream().anyMatch(each -> (boolean)eval(each)));
  138.     addSpecialForm("and", args -> args.stream().allMatch(each -> (boolean)eval(each)));
  139.     addSpecialForm("if", args -> (boolean) eval(args.get(0))
  140.               ? eval(args.get(1))
  141.               : (args.size() > 2 ? eval(args.get(2)) : null));
  142.   }
  143.  
  144.   public void addFunction(String name, Func func) {
  145.     functions.put(name, func);
  146.   }
  147.  
  148.   public void addSpecialForm(String name, SpecialForm func) {
  149.     specialForms.put(name, func);
  150.   }
  151.  
  152.   public Object eval(AST ast) {
  153.     if (ast.isAtom()) {
  154.       try {
  155.         return ast.numValue();
  156.       } catch (NumberFormatException e) {
  157.         return ast.boolValue();
  158.       }
  159.     }
  160.     SpecialForm specialForm = specialForms.get(ast.head().token());
  161.     if (specialForm != null) {
  162.       return specialForm.call(ast.tail());
  163.     }
  164.     Func func = functions.get(ast.head().token());
  165.     if (func == null)
  166.       throw new RuntimeException("Unknown function: " + ast.head().token());
  167.     return func.call(ast.tail().stream().map(this::eval).collect(toList()));
  168.   }
  169. }
Advertisement
Add Comment
Please, Sign In to add comment