/*
 * This file is part of Jehanne.
 *
 * Copyright (C) 2016 Giacomo Tesio <giacomo@tesio.it>
 *
 * Jehanne 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, version 2 of the License.
 *
 * Jehanne 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 Jehanne.  If not, see <http://www.gnu.org/licenses/>.
 */

/*
 * this program makes the table to link function names
 * and type indices that is used by execute() in run.c.
 * it finds the indices in y.tab.h, produced by yacc.
 */

package main

import (
	"bufio"
	"log"
	"os"
	"strings"
	"strconv"
	"text/template"
)

type Flist struct {
	Token	string
	Name	string
	Pname	string
}

var flist = []Flist {
	{ "PROGRAM", "program", "" },
	{ "BOR", "boolop", " || " },
	{ "AND", "boolop", " && " },
	{ "NOT", "boolop", " !" },
	{ "NE", "relop", " != " },
	{ "EQ", "relop", " == " },
	{ "LE", "relop", " <= " },
	{ "LT", "relop", " < " },
	{ "GE", "relop", " >= " },
	{ "GT", "relop", " > " },
	{ "ARRAY", "array", "" },
	{ "INDIRECT", "indirect", "$(" },
	{ "SUBSTR", "substr", "substr" },
	{ "SUB", "sub", "sub" },
	{ "GSUB", "gsub", "gsub" },
	{ "INDEX", "sindex", "sindex" },
	{ "SPRINTF", "awksprintf", "sprintf" },
	{ "ADD", "arith", " + " },
	{ "MINUS", "arith", " - " },
	{ "MULT", "arith", " * " },
	{ "DIVIDE", "arith", " / " },
	{ "MOD", "arith", " % " },
	{ "UMINUS", "arith", " -" },
	{ "POWER", "arith", " **" },
	{ "PREINCR", "incrdecr", "++" },
	{ "POSTINCR", "incrdecr", "++" },
	{ "PREDECR", "incrdecr", "--" },
	{ "POSTDECR", "incrdecr", "--" },
	{ "CAT", "cat", " " },
	{ "PASTAT", "pastat", "" },
	{ "PASTAT2", "dopa2", "" },
	{ "MATCH", "matchop", " ~ " },
	{ "NOTMATCH", "matchop", " !~ " },
	{ "MATCHFCN", "matchop", "matchop" },
	{ "INTEST", "intest", "intest" },
	{ "PRINTF", "awkprintf", "printf" },
	{ "PRINT", "printstat", "print" },
	{ "CLOSE", "closefile", "closefile" },
	{ "DELETE", "awkdelete", "awkdelete" },
	{ "SPLIT", "split", "split" },
	{ "ASSIGN", "assign", " = " },
	{ "ADDEQ", "assign", " += " },
	{ "SUBEQ", "assign", " -= " },
	{ "MULTEQ", "assign", " *= " },
	{ "DIVEQ", "assign", " /= " },
	{ "MODEQ", "assign", " %= " },
	{ "POWEQ", "assign", " ^= " },
	{ "CONDEXPR", "condexpr", " ?: " },
	{ "IF", "ifstat", "if(" },
	{ "WHILE", "whilestat", "while(" },
	{ "FOR", "forstat", "for(" },
	{ "DO", "dostat", "do" },
	{ "IN", "instat", "instat" },
	{ "NEXT", "jump", "next" },
	{ "NEXTFILE", "jump", "nextfile" },
	{ "EXIT", "jump", "exit" },
	{ "BREAK", "jump", "break" },
	{ "CONTINUE", "jump", "continue" },
	{ "RETURN", "jump", "ret" },
	{ "BLTIN", "bltin", "bltin" },
	{ "CALL", "call", "call" },
	{ "ARG", "arg", "arg" },
	{ "VARNF", "getnf", "NF" },
	{ "GETLINE", "getline", "getline" },
	{ "", "", "" },
}

type Proctab struct {
	Code	int
	Name	string
	Func	string
}

func getf(token string) Flist {
	for i := range flist {
		if token == flist[i].Token {
			return flist[i]
		}
	}
	return Flist{"","nullproc",""}
}

func main() {
    file, err := os.Open("y.tab.h")
    if err != nil {
        log.Fatal(err)
    }
    defer file.Close()
    
    proctab := make([]Proctab, 0)

    scanner := bufio.NewScanner(file)
    for scanner.Scan() {
	s := scanner.Text()
	if strings.Contains(s, "#define") {
		tokens := strings.Split(s, " ");
		i, err := strconv.Atoi(tokens[2])
		if err == nil {
			f := getf(tokens[1])
			proctab = append(proctab, Proctab{i, tokens[1], f.Name})
		}
	}
    }
    

    if err := scanner.Err(); err != nil {
        log.Fatal(err)
    }

	tmpl, err := template.New("proctab.c").Parse(`/* automatically generated by maketab */
#include <u.h>
#include <lib9.h>
#include <bio.h>
#include "awk.h"
#include "y.tab.h"

static char *printname[{{len .}}] = {
{{ range . }}	(char *) "{{.Name}}",	/* {{.Code}} */
{{ end }}
};

Cell *(*proctab[{{len .}}])(Node **, int) = {
{{ range . }}	{{.Func}},	/* {{.Name}} */
{{ end }}
};

char *
tokname(int n)
{
	static char buf[100];

	if (n < FIRSTTOKEN || n > LASTTOKEN) {
		sprint(buf, "token %d", n);
		return buf;
	}
	return printname[n-FIRSTTOKEN];
}
`)
	if err != nil {
		log.Fatal(err)
	}

	err = tmpl.Execute(os.Stdout, proctab)
	if err != nil {
		log.Fatal(err)
	}
}
