public void Visit(Program program)
        {
            // the init op code sets up the call stack, to read command line arguments
            var main = program.Definitions.Single(d => d.Name == "main");

            tacs.Add(Tac.Init(main.Formals.Count));
            // call main
            tacs.Add(Tac.BeginCall(main.Name, main.Formals.Count, "t0"));
            for (int i = 0; i < main.Formals.Count; i++)
            {
                tacs.Add(Tac.Param($"arg{i}"));
            }
            tacs.Add(Tac.Call("main", "t0"));
            // call print
            tacs.Add(Tac.BeginCall("print", 1, "t1"));
            tacs.Add(Tac.Param("t0"));
            tacs.Add(Tac.Call("print", "t1"));
            tacs.Add(Tac.Halt());

            // declare print function
            tacs.Add(Tac.BeginFunc("print", 1));
            tacs.Add(Tac.PrintVariable("arg0"));
            tacs.Add(Tac.EndFunc("print"));

            foreach (var definition in program.Definitions)
            {
                definition.Accept(this);
            }
        }
        public void Visit(Print print)
        {
            print.Expr.Accept(this);
            var temp           = tacs.Last().Result;
            var returnVariable = MakeNewTemp();

            tacs.Add(Tac.BeginCall("print", 1, returnVariable));
            tacs.Add(Tac.Param(temp));
            tacs.Add(Tac.Call("print", returnVariable));
        }
        public void Visit(FunctionCall functionCall)
        {
            var args = new List <string>();

            foreach (var actual in functionCall.Actuals)
            {
                actual.Expr.Accept(this);
                args.Add(tacs.Last().Result);
            }

            var returnValue = MakeNewTemp();

            tacs.Add(Tac.BeginCall(functionCall.Name, functionCall.Actuals.Count, returnValue));
            foreach (var arg in args)
            {
                tacs.Add(Tac.Param(arg));
            }
            tacs.Add(Tac.Call(functionCall.Name, returnValue));
        }