language: ocaml prompt: https://adventofcode.com/2020/day/18 learn: https://ocaml.org/learn/


solve.ml

open Printf;;

let lexed_file f =
    Lexing.from_channel (open_in f)
;;

let rec eval lexbuf acc =
    try
        eval lexbuf (acc + (Parser.main Lexer.token lexbuf))
    with Lexer.Eof ->
        acc
;;

let lexbuf = lexed_file "./input" in
let final_sum = eval lexbuf 0 in

printf "Final result: %d\n" final_sum



lexer.mll

{
    open Parser
    exception Eof
}

rule token = parse
    [' '] { token lexbuf }
    | ['\n'] { EOL }
    | ['0'-'9']+ as digits { INT(int_of_string digits) }
    | '+' { PLUS }
    | '*' { TIMES }
    | '(' { LPAREN }
    | ')' { RPAREN }
    | eof { raise Eof }



parser-part1.mly

%token <int> INT
%token PLUS TIMES
%token LPAREN RPAREN
%token EOL
%left PLUS TIMES
%start main
%type <int> main
%%

main:
    expr EOL {$1}
;

expr:
    INT {$1}
    | LPAREN expr RPAREN {$2}
    | expr PLUS expr {$1 + $3}
    | expr TIMES expr {$1 * $3}
    | EOL {0}
;


parser-part2.mly

%token <int> INT
%token PLUS TIMES
%token LPAREN RPAREN
%token EOL
%left TIMES /* Only these    */
%left PLUS  /* lines change. */
%start main
%type <int> main
%%

main:
    expr EOL {$1}
;

expr:
    INT {$1}
    | LPAREN expr RPAREN {$2}
    | expr PLUS expr {$1 + $3}
    | expr TIMES expr {$1 * $3}
    | EOL {0}
;



run

#!/bin/bash

# Update based on part to solve:
#ln -sf parser-part1.mly parser.mly
ln -sf parser-part2.mly parser.mly

ocamllex lexer.mll \
  && ocamlyacc parser.mly \
  && ocamlc -c parser.mli \
  && ocamlc -c lexer.ml \
  && ocamlc -c parser.ml \
  && ocamlc -c solve.ml \
  && ocamlc lexer.cmo parser.cmo solve.cmo -o solve \
  && ./solve



See also: