#!/usr/bin/awk -f
#

#
# Notas importantes
#
BEGIN {
notas = "\
1. Conjugue 1.1 presta-se basicamente para gerar um dicionário\n\
para ser usado em verificadores ortográficos. Por isso, os tempos\n\
compostos não são considerados.\n\
\n\
2. O programa chama de irregulares alguns verbos que os\n\
gramáticos consideram regulares, e vice-versa. Na medida do\n\
possível tentaremos sanar essas diferenças (ou ao menos\n\
precisá-las) nas próximas versões.\n\
\n\
3. O programa conjugará qualquer verbo não pronominal da língua\n\
portuguesa, mesmo os que não constam do banco. O paradigma,\n\
quando não é conhecido, é deduzido heuristicamente. Não disponho\n\
de exemplos em que a heurística falha, mas não deve ser difícil\n\
conseguir alguns.\n\
\n\
4. Todas as vezes em que você tentar conjugar um verbo que não\n\
consta no banco, ele será concatenado ao arquivo\n\
$HOME/.conjugue-novos (o programa *não* acrescenta o conteúdo\n\
desse arquivo ao banco quando o banco é carregado logo após o\n\
disparo do programa)."
}

#
# Notas sobre a implementação
# ---------------------------
#
# Os verbos conhecidos pelo programa são as entradas do
# vetor associativo V. O valor da entrada pode ser a string
# nula, uma lista de tempos e/ou modos com a forma de
# flexionar o verbo nesses tempos e/ou modos ou um outro
# verbo, eventualmente seguido por formas alternativas
# do particípio (separador ":").
#
# No primeiro caso, o verbo é flexionado segundo os paradigmas
# regulares. No segundo também, exceto naqueles tempos e/ou
# modos explicitados, e no terceiro ele é conjugado tomando-se
# o verbo indicado como modelo (e adicionando-se a(s) eventual(is)
# forma(s) alternativa(s) do particípio).
#
#
# faltam:
# -------
#
# conjugação de verbos pronominais
# suporte para formas abundantes (particípios ok)
# leitura da lista de verbos novos após o carregamento do banco
#

#
# Lista de tempos e modos
#
BEGIN {
abrevia = "\
FN - formas nominais: infinitivo, gerúndio e particípio\n\
IP - infinitivo pessoal\n\
\n\
PI - presente do indicativo\n\
II - imperfeito do indicativo\n\
EI - perfeito do indicativo\n\
MI - mais-que-perfeito do indicativo\n\
TI - futuro do pretérito do indicativo\n\
FI - futuro do presente do indicativo\n\
\n\
PS - presente do subjuntivo\n\
IS - imperfeito do subjuntivo\n\
FS - futuro do subjuntivo\n\
\n\
IA - imperativo afirmativo\n\
IN - imperativo negativo"
}

#
# Verifica se o radical é prefixo de cada conjugação da lista. Retorna
# "R" em caso afirmativo, ou "" caso contrário (isso é uma reminiscência
# histórica).
#
function checa_radical(verbo,r,c,n,t,i,mpc,l) {

    # determina o maior prefixo do radical comum a todas as formas
    n = split(c,t,":")
    mpc = r
    for (i=1; i <= n; ++i)
        if (t[i] != "")
            while (match(t[i],mpc) != 1) mpc = substr(mpc,1,length(mpc)-1)
    if (match(mpc,r) > 0)
        return("R")
    else
        return("")
}

#
# Essa função recebe o radical e a conjugação como primeiro
# e segundo parâmetros, e classifica o tipo de alteração
# do radical atribuindo-lhe um código numérico.
#
# Por exemplo: se a última vogal de um radical for "o" (como
# em "dorm+ir"), então o código zero associado a esse radical
# indica que essa vogal deve ser trocada por "u" (como em
# "durm+a").
#
# Um mesmo código pode ser utilizado para referir várias
# transformações diferentes, desde que a vogal inicial e a
# vogal resultante ocorram como tais uma única vez sob esse
# código (em outras palavras, cada código deve definir uma
# bijeção).
#
# Para incluir uma nova substituição de vogais sob um código já
# existente, basta adicionar o teste contendo as duas vogais,
# usando como exemplo as transformações já relacionadas.
#
# Se não for possível incluir a substituição sob um código já
# existente, será necessário criar um novo código. Atualmente
# só se podem usar como códigos os dígitos decimais (0-9),
# sendo que os dígitos de 0 a 6 (inclusive) estão em uso.
#
# Em qualquer caso, é necessário incluir a substituição
# inversa na rotina "desnormaliza". Se isso não for feito,
# a mensagem "vogal v inválida para regra n e radical r"
# será exibida.
#
# Note que a acentuação gráfica precisa ser considerada como
# substituição de vogal (proibir > proíbe).
#
function normaliza(r,c,t,i,j,k,l,v,w,m,n,x,y,u,pi,ri,pk,rk) {

    # quebra a conjugação nas várias pessoas
    n = split(c,t,":")

    # tamanho e última letra do radical
    l = length(r);
    u = substr(r,l,1);

    # obtém em i a posição da última vogal do radical
    for (i=l; (i >= 1) && (!(substr(r,i,1) in VOG)); --i);

    # idem, em k, desconsiderando a última letra do radical
    for (k=l-1; (k >= 1) && (!(substr(r,k,1) in VOG)); --k);

    # se existirem essas vogais armazene-as em v e x
    if (i >= 1) {
        v = substr(r,i,1)
    }
    if (k >= 1) {
        x = substr(r,k,1)
    }

    #
    # .. para cada pessoa tente classificar a alteração do radical
    # dentro dos casos conhecidos. A conjugação é então alterada
    # da forma
    #     "radical alterado" "sufixo"
    # para a forma
    #     "radical" "sufixo" "código"
    #
    c = ""
    for (j=1; j<=n; ++j) {
    
        w = substr(t[j],i,1);
        y = substr(t[j],k,1)

        # prefixos e restos relativos à i-ésima e k-ésima letras
        pi = substr(t[j],1,i-1)
        ri = substr(t[j],i+1,l-i)
        pk = substr(t[j],1,k-1)
        rk = substr(t[j],k+1,l-k-1)

        # regra 0: substitua a última vogal do radical
        #     de a para e, ou
        #     de o para u (dormir > durma), ou
        #     de u para o (cuspir > cospe), ou
        #     de e para i (ferir  > fira),
        #     de i para í (proibir  > proíbe),
        # e verifique se se obtém o radical
        if ((i > 0) &&
        (((w == "e") && (pi "a" ri == r)) ||
        ((w == "o") && (pi "u" ri == r)) ||
        ((w == "í") && (pi "i" ri == r)) ||
        ((w == "u") && (pi "o" ri == r)) ||
        ((w == "i") && (pi "e" ri == r)))) {
            t[j] = pi v substr(t[j],i+1) "0"
            #print "regra 0 aplicada para transformar " r " em " t[j]
        }

        # regra 1: substitua a última vogal do radical
        #     de a para i (fazer > fizer), ou
        #     de o para ô (voar > vôo), ou
        #     de u para ú (saudar > saúdo),
        # e verifique se se obtém o radical
        else if ((i > 0) &&
        (((w == "i") && (pi "a" ri == r)) ||
        ((w == "ú") && (pi "u" ri == r)) ||
        ((w == "ô") && (pi "o" ri == r))))
            t[j] = pi v substr(t[j],i+1) "1"
    
        # regra 2: desconsidere a última letra do radical e substitua a
        # última vogal
        #     de a para o (trazer > trouxe), ou
        #     de e para i (convergir > convirja)
        #     de o para u (moscar > musque)
        # e verifique se se obtém o radical (a menos da última letra).
        else if ((k > 0) &&
        (((y == "i") && (pk "e" rk u == r)) ||
        ((y == "u") && (pk "o" rk u == r)) ||
        ((y == "o") && (pk "a" rk u == r))))
            t[j] = r substr(t[j],l) "2"

        # regra 3: desconsidere a última letra do radical e substitua a
        # última vogal
        #     de a para á (haver > há)
        #     de o para ó (apoiar > apóio)
        # e verifique se se obtém o radical (a menos da última letra).
        else if ((k > 0) &&
        (((y == "á") && (pk "a" rk u == r)) ||
        ((y == "ó") && (pk "o" rk u == r))))
            t[j] = r substr(t[j],l) "3"

        # regra 4: desconsidere a última letra do radical e substitua a
        # última vogal
        #     de a para ã (haver > hão)
        # e verifique se se obtém o radical (a menos da última letra).
        else if ((k > 0) &&
        ((y == "ã") && (pk "a" rk u == r)))
            t[j] = r substr(t[j],l) "4"

        # regra 5: desconsidere a última letra do radical e substitua a
        # última vogal
        #     de a para e (saber > sei)
        # e verifique se se obtém o radical (a menos da última letra).
        else if ((k > 0) &&
        ((y == "e") && (pk "a" rk u == r)))
            t[j] = r substr(t[j],l) "5"

        # regra 6: desconsidere a última letra do radical e verifique
        # se se obtém o radical, desconsiderada a última letra (ouvir > ouça).
        else if ((substr(t[j],1,l-1) == substr(r,1,l-1)) && (substr(t[j],1,l) != substr(r,1,l)))
            t[j] = r substr(t[j],l) "6"

        # todas as regras conhecidas falharam
        else if ((t[j] != "") && (substr(t[j],1,l) != substr(r,1,l)))
            print "vogal não normalizada: w=" w ", y=" y " (" r ":" t[j] ")"
    
        # concatena em c a nova forma da conjugação da pessoa corrente
        c = c ((j>1) ? ":" : "") t[j]
    }

    return(c)
}

#
# desnormaliza um radical, isto é, aplica a regra inversa segundo
# as definições da rotina de normalização. Recebe em r o radical e
# em f o código da transformação. Veja a documentação da função
# "normaliza" para detalhes.
#
function desnormaliza(r,f,i,v) {

    # casos onde se trabalha com o radical inteiro
    if (f < 2) {

        # obtém em i a posição da última vogal do radical, e a vogal
        for (i=length(r); (i >= 1) && (!(substr(r,i,1) in VOG)); --i);
        v = substr(r,i,1)

        # substitui a última vogal conforme a regra
        if (f == "0") {
            if (v == "a")
                r = substr(r,1,i-1) "e" substr(r,i+1)
            else if (v == "o")
                r = substr(r,1,i-1) "u" substr(r,i+1)
            else if (v == "u")
                r = substr(r,1,i-1) "o" substr(r,i+1)
            else if (v == "i")
                r = substr(r,1,i-1) "í" substr(r,i+1)
            else if (v == "e")
                r = substr(r,1,i-1) "i" substr(r,i+1)
            else
                print "vogal " v " inválida para regra " f " e radical " r
        }
        else if (f == 1) {
            if (v == "a")
                r = substr(r,1,i-1) "i" substr(r,i+1)
            else if (v == "o")
                r = substr(r,1,i-1) "ô" substr(r,i+1)
            else if (v == "u")
                r = substr(r,1,i-1) "ú" substr(r,i+1)
            else
                print "vogal " v " inválida para regra " f " e radical " r
        }
    }

    # casos onde se trabalha com o radical a menos da última letra
    else {

        #print "radical submetido: " r

        # remove a última letra do radical
        r = substr(r,1,length(r)-1);

        #print "radical sem a última letra: " r

        # obtém em última vogal do radical reduzido e sua posição
        for (i=length(r); (i >= 1) && (!(substr(r,i,1) in VOG)); --i);
        v = substr(r,i,1)

        # substitui a última vogal conforme a regra
        if (f == "2") {
            if (v == "a")
                r = substr(r,1,i-1) "o" substr(r,i+1)
            else if (v == "e")
                r = substr(r,1,i-1) "i" substr(r,i+1)
            else if (v == "o")
                r = substr(r,1,i-1) "u" substr(r,i+1)
            else
                print "vogal " v " inválida para regra " f " e radical " r
        }
        if (f == "3") {
            if (v == "a")
                r = substr(r,1,i-1) "á" substr(r,i+1)
            else if (v == "o")
                r = substr(r,1,i-1) "ó" substr(r,i+1)
            else
                print "vogal " v " inválida para regra " f " e radical " r
        }
        if (f == "4") {
            if (v == "a")
                r = substr(r,1,i-1) "ã" substr(r,i+1)
            else
                print "vogal " v " inválida para regra " f " e radical " r
        }
        if (f == "5") {
            if (v == "a")
                r = substr(r,1,i-1) "e" substr(r,i+1)
            else
                print "vogal " v " inválida para regra " f " e radical " r
        }
    }
    return(r)
}

#
# Fatora a conjugação pelo radical, indicando para cada pessoa
# a terminação e a correção do radical, se houver.
#
function fatora_prefixos(verbo,lista,t,mpc,i,R,D,l,lf,j,n,c) {

    # transforma o mpc numa função do radical
    R = substr(verbo,1,(l=length(verbo))-2)
    D = substr(R,1,l-3)
    mpc = checa_radical(verbo,R,lista)

    if (mpc == "") {
        lista = normaliza(R,lista)
        mpc = checa_radical(verbo,R,lista)
    }
    if (mpc == "") {
        j = 1
        print "cuidado: mpc do verbo " verbo " (" lista ") não resolvido"
    }

    # constrói a lista fatorada
    n = split(lista,t,":")
    j = length(verbo)-1;
    for (i=1; i<=n; ++i) {
        if (i > 1) lf = lf ":"
        c = substr(t[i],length(t[i]));
        lf = lf ((t[i] == "") ? "-" : substr(t[i],j))
    }
    return(lf)
}

#
# A partir da conjugação do verbo, cria um modelo que permite
# aplicar a mesma conjugação em outros verbos.
#
function cria_modelo(verbo,t,i,n) {

    n = split(V[verbo],t,"\n")
    V[verbo] = ""
    for (i=1; i<=n; ++i) {
        t[i] = substr(t[i],1,3) fatora_prefixos(verbo,substr(t[i],4))
        if (i > 1) V[verbo] = V[verbo] "\n"
        V[verbo] = V[verbo] t[i]
    }
}

#
# Carrega o banco indicado criando entradas do vetor V. O
# formato do banco está descrito na man page do conjugue.
#
function carrega_banco(banco,a,b,n,l,vt,p,k) {

    # contadores de paradigmas, verbos e linhas
    n = m = l = 0

    # estado da leitura
    estado = "nulo"

    # loop de leitura de linhas
    while ((getline <banco) > 0) {

        # contabiliza a linha recém-lida
        ++l

        # despreza linhas vazias e comentários
        if ((NF > 0) && ((a=substr($0,1,1)) != "#")) {

            # continua lendo paradigma ou inicia leitura da lista
            if (estado == "lendo_paradigma") {

                # uma parte da conjugação do paradigma atual
                if (substr($0,1,2) in TM) {
                    if (V[paradigma] == "")
                        V[paradigma] = $0
                    else
                        V[paradigma] = V[paradigma] "\n" $0
                }

                # concluída leitura do paradigma
                else {
                    cria_modelo(paradigma)
                    estado = "lendo_lista"
                }
            }

            # continua lendo lista ou volta ao estado nulo
            if (estado == "lendo_lista") {

                # verbo da lista do paradigma atual
                if (match($0,":") == 0)
                    if (substr($1,length($1),1) == "r") {
                        if ($1 in V) {
                            V[$1] = paradigma ":" V[$1]
                            print "ocorrência múltipla de " $1
                        }
                        else
                            V[$1] = paradigma
                        ++m
                    }
                    else {
                        print "conjugue: erro na linha " l " do banco"
                        print $0 " não é verbo"
                    }

                # concluída leitura da lista de verbos
                else
                    estado = "nulo"
            }

            # procura paradigma ou verbo abundante
            if (estado == "nulo") {

                # isola paradigma
                if ((a=substr($0,1,9)) == "paradigma") {
                    if ((k=split($0,p,":")) > 2)
                        LP[p[2]] = p[3]
                    paradigma = (k > 1) ? p[2] : ""
                    if (paradigma in V) {
                        print "conjugue: erro fatal na linha " l " do banco"
                        print "paradigma " paradigma "já ocorreu antes"
                        exit
                    }
                    ++n
                    estado = "lendo_paradigma"

                    # o primeiro paradigma de cada conjugação é o regular
                    vt = substr(paradigma,length(paradigma)-1,1)
                    if (pr[vt] == "")
                        pr[vt] = paradigma
                }

                # isola verbo abundante
                else if (a == "abundante") {

                    if (split($0,p,":") != 3) {
                        print "conjugue: erro fatal na linha " l " do banco"
                        print "sintaxe incorreta para forma abundante"
                        exit 1
	            }

                    if (p[2] in V)
                        V[p[2]] = V[p[2]] ":" p[3]
                    else
                        V[p[2]] = ":" p[3]
          
                }

                # erro no banco
                else {
                    print "conjugue: erro fatal na linha " l " do banco"
                    print "esperado \"paradigma\" ou \"abundante\""
                    exit 1
                }

            }
        }
    }
    if ((FORMATO !~ /^c/) && (CMD == "")) {
        print "lidos " n " paradigmas"
        print "lidos " m+n " verbos"
    }
}

#
# Expande uma string abreviada. Isso significa basicamente
# prefixar cada componente de c (as componentes são
# separadas por ":") pelo radical r, alterado segundo a
# regra indicada.
#
function expande(c,r,v,i,j,l,p,q,z,f) {

    p = substr(p,2,i-2)
    i = split(substr(c,i+1),z,":")
    c = ""
    for (j=1; j <= i; ++j) {
        f = substr(z[j],length(z[j]))
        if ((f >= "0") && (f <= "9"))
            c = c ":" desnormaliza(r,f) p substr(z[j],1,length(z[j])-1)
        else
            c = c ":" ((z[j] == "-") ? "" : r p z[j])
    }
    c = substr(c,2,length(c)-1)
    return c
}

#
# Conjuga o verbo dado em todos os modos e tempos
#
function conjugue_todos(verbo,r,vt,tmr,tme,i,p,a,k,l,t,reg,C,cs,pp) {

    # Obtenção da raiz e da vogal temática
    l = length(verbo)
    r = substr(verbo,1,l-2)
    vt = substr(verbo,l-1,1)

    # Obtenção do paradigma regular
    cpr = V[pr[vt]]

    # O verbo conta com uma lista específica de tempos/modos
    if (substr(V[verbo],1,2) in TM) {
        esp = V[verbo]
	if (pr[vt] == verbo) {
            if (FORMATO !~ /^c/)
                print "# paradigma regular"
            reg = 1;
        }
        else {
            if (FORMATO !~ /^c/)
                print "# paradigma irregular"
            reg = 0
        }
    }

    # O verbo é conjugado segundo o paradigma explicitado
    else {
        a = split(V[verbo],p,":")

        # Temos que deduzir um paradigma
        if (p[1] == "") {
            t = 0
            for (i in LP) {
                k = length(LP[i])
                if ((LP[i] != "") && (k > t) && (substr(verbo,l-k+1) == LP[i])) {
                    p[1] = i
                    t = k
                }
            }
            if (pr[vt] == p[1]) {
                if (FORMATO !~ /^c/)
                    print "# paradigma deduzido: " p[1] " (regular)"
                reg = 1
            }
            else {
                if (FORMATO !~ /^c/)
                    print "# paradigma deduzido: " p[1] " (irregular)"
                reg = 0
            }
        }

        # o paradigma foi explicitado
        else {
            if (pr[vt] == p[1]) {
                if (FORMATO !~ /^c/)
                    print "# paradigma: " p[1] " (regular)"
                reg = 1
            }
            else {
                if (FORMATO !~ /^c/)
                    print "# paradigma: " p[1] " (irregular)"
                reg = 0
            }
        }

        # obtém regras específicas do paradigma
        esp = V[p[1]]
    }

    # Correção do regular pelo específico
    n = split(cpr,tmr,"\n")
    m = split(esp,tme,"\n")
    if ((m < n) && (FORMATO !~ /^c/) && (CMD == ""))
        print "# regular em " n-m " casos"
    for (i=1; i<=n; ++i)
        tmr[substr(tmr[i],1,2)] = tmr[i]
    for (i=1; i<=m; ++i)
        tmr[substr(tme[i],1,2)] = tme[i]

    # Adição das formas alternativas do particípio
    if (("FN" in tmr) && (a > 1)) {
        tmr["FN"] = "FN:" expande(substr(tmr["FN"],4),r,verbo)
        while (a > 1) tmr["FN"] = tmr["FN"] "," p[a--]
    }

    # formato curto com flags do br.ispell
    if (FORMATO=="ci") {

        if (reg == 1)
            print verbo "/R/T/F/N/C"

        else {

            #
            # Neste ponto o conjugue gera algumas formas
            # enclíticas. Note que aqui só são tratados verbos
            # irregulares. De fato, o caso regular é tratado
            # no br.aff pela flag C. A documentação da flag C
            # no br.aff contém muitas informações adicionais.
            #

            # formas enclíticas dos tempos compostos
            if (vt == "a")
                print r "á"
            else if (vt == "e")
                print r "ê"
            else if (vt == "o")
                print r "ô"

            # formas enclíticas da primeira do plural, vários tempos
            C = expande(substr(tmr["PI"],4),r,verbo)
            n = split(C,pp,":")
            if (pp[4] != "")
                print substr(pp[4],0,length(pp[4])-1);
            C = expande(substr(tmr["PS"],4),r,verbo)
            n = split(C,pp,":")
            if (pp[4] != "")
                print substr(pp[4],0,length(pp[4])-1);
            C = expande(substr(tmr["FS"],4),r,verbo)
            n = split(C,pp,":")
            if (pp[4] != "")
                print substr(pp[4],0,length(pp[4])-1);
            C = expande(substr(tmr["FI"],4),r,verbo)
            n = split(C,pp,":")
            if (pp[4] != "")
                print substr(pp[4],0,length(pp[4])-1);

            if ((verbo == "passear") || (p[1] == "passear"))
                print verbo "/R/S/F"

            else if ((verbo == "conhecer") || (p[1] == "conhecer"))
                print verbo "/R/S/F"

            # O br.aff não é capaz de gerar as conjugações corretas dos verbos
            # cujo paradigma é ferir, por isso estamos gerando a flag /S apenas
            # para o verbo ferir.
            else if (verbo ~ "ferir")
                print verbo "/R/S/F"

            else if ((verbo == "comunicar") || (p[1] == "comunicar"))
                print verbo "/R/Q/N"

            else if ((verbo == "cegar") || (p[1] == "cegar"))
                print verbo "/R/A/N"

            else if ((verbo == "abraçar") || (p[1] == "abraçar"))
                print verbo "/R/B/N"

            else if ((verbo == "magoar") || (p[1] == "magoar"))
                print verbo "/R/M/F"

            else if ((verbo == "abolir") || (p[1] == "abolir"))
                print verbo "/R/M/F"

            else {
                for (i in TM) {
                    C = expande(substr(tmr[i],4),r,verbo)
                    gsub(":","\n",C)
                    print C
                }
            }
        }
    }

    # formato curto
    else if (FORMATO=="c") {

        for (i in TM) {
            C = expande(substr(tmr[i],4),r,verbo)
            gsub(":","\n",C)
            print C
        }
    }

    # formato normal
    else if (FORMATO ~ /^n/) {

        for (i in TM) {
            C = expande(substr(tmr[i],4),r,verbo)
            print i ":" C
        }
    }

    # formato para debugação (exibe a regra de formação)
    else if (FORMATO ~ /^d/) {

        for (i in TM) {
            print i ":" substr(tmr[i],4)
        }
    }

    # formato longo (default)
    else if ((FORMATO == "l") || (FORMATO == "")) {

        for (i in TM) {
            C = expande(substr(tmr[i],4),r,verbo)
            print TM[i] ":" C
        }
    }

    # formato muito longo
    else if (FORMATO == "ll") {

        # formas nominais
        print TM["FN"]
        C = expande(substr(tmr["FN"],4),r,verbo)
        split(C,cs,":");
        print "   infinitivo: " cs[1]
        print "   gerúndio: " cs[2]
        print "   particípio: " cs[3]

        # presente do indicativo
        print TM["PI"]
        C = expande(substr(tmr["PI"],4),r,verbo)
        split(C,cs,":");
        for (j=1; j<=6; ++j) {
            if (cs[j] ne "")
                print "   " P[j] " " cs[j]
        }

        # imperfeito do indicativo
        print TM["II"]
        C = expande(substr(tmr["II"],4),r,verbo)
        split(C,cs,":");
        for (j=1; j<=6; ++j) {
            if (cs[j] ne "")
                print "   " P[j] " " cs[j]
        }

        # perfeito do indicativo
        print TM["EI"]
        C = expande(substr(tmr["EI"],4),r,verbo)
        split(C,cs,":");
        for (j=1; j<=6; ++j) {
            if (cs[j] ne "")
                print "   " P[j] " " cs[j]
        }

        # mais-que-perfeito do indicativo
        print TM["MI"]
        C = expande(substr(tmr["MI"],4),r,verbo)
        split(C,cs,":");
        for (j=1; j<=6; ++j) {
            if (cs[j] ne "")
                print "   " P[j] " " cs[j]
        }

        # futuro do pretérito do indicativo
        print TM["TI"]
        C = expande(substr(tmr["TI"],4),r,verbo)
        split(C,cs,":");
        for (j=1; j<=6; ++j) {
            if (cs[j] ne "")
                print "   " P[j] " " cs[j]
        }

        # futuro do presente do indicativo
        print TM["FI"]
        C = expande(substr(tmr["FI"],4),r,verbo)
        split(C,cs,":");
        for (j=1; j<=6; ++j) {
            if (cs[j] ne "")
                print "   " P[j] " " cs[j]
        }

        # no presente do subjuntivo adicionamos "que"
        print TM["PS"]
        C = expande(substr(tmr["PS"],4),r,verbo)
        split(C,cs,":");
        for (j=1; j<=6; ++j) {
            if (cs[j] ne "")
                print "   que " P[j] " " cs[j]
        }
	
        # no imperfeito do subjuntivo adicionamos "se"
        print TM["IS"]
        C = expande(substr(tmr["IS"],4),r,verbo)
        split(C,cs,":");
        for (j=1; j<=6; ++j) {
            if (cs[j] ne "")
                print "   se " P[j] " " cs[j]
        }
	
        # no futuro do subjuntivo adicionamos "quando"
        print TM["FS"]
        C = expande(substr(tmr["FS"],4),r,verbo)
        split(C,cs,":");
        for (j=1; j<=6; ++j) {
            if (cs[j] ne "")
                print "   quando " P[j] " " cs[j]
        }
	
        # imperativo afirmativo
        print TM["IA"]
        C = expande(substr(tmr["IA"],4),r,verbo)
        split(C,cs,":");
        for (j=2; j<=6; ++j) {
            if (cs[j-1] ne "")
                print "   " cs[j-1] " " P[j]
        }
	
        # imperativo negativo
        print TM["IN"]
        C = expande(substr(tmr["IN"],4),r,verbo)
        split(C,cs,":");
        for (j=2; j<=6; ++j) {
            if (cs[j-1] ne "")
                print "   não " cs[j-1] " " P[j]
        }
	
        # no infinitivo pessoal adicionamos "por"
        print TM["IP"]
        C = expande(substr(tmr["IP"],4),r,verbo)
        split(C,cs,":");
        for (j=1; j<=6; ++j) {
            if (cs[j] ne "")
                print "   por " cs[j] " " P[j]
        }
    }
}

#
# Inicializa alguns conjuntos
#
function inicializa_tm() {

    TM["FN"] = "Formas Nominais:"
    TM["IP"] = "Infinitivo Pessoal"
    TM["PI"] = "Presente do Indicativo"
    TM["II"] = "Imperfeito do Indicativo"
    TM["EI"] = "Perfeito do Indicativo"
    TM["MI"] = "Mais-que-perfeito do Indicativo"
    TM["TI"] = "Futuro do Pretérito do Indicativo"
    TM["FI"] = "Futuro do Presente do Indicativo"
    TM["PS"] = "Presente do Subjuntivo"
    TM["IS"] = "Imperfeito do Subjuntivo"
    TM["FS"] = "Futuro do Subjuntivo"
    TM["IA"] = "Imperativo Afirmativo"
    TM["IN"] = "Imperativo Negativo"
    VOG["a"] = ""
    VOG["e"] = ""
    VOG["i"] = ""
    VOG["o"] = ""
    VOG["u"] = ""
    VOG["ã"] = ""
    VOG["õ"] = ""
    VOG["ô"] = ""
    VOG["á"] = ""
    VOG["é"] = ""
    VOG["í"] = ""
    VOG["ó"] = ""
    VOG["ú"] = ""
    P["1"] = "eu"
    P["2"] = "tu"
    P["3"] = "ele"
    P["4"] = "nós"
    P["5"] = "vós"
    P["6"] = "eles"
}

#
# O programa começa aqui
#
BEGIN {

    #
    # comando "T" subentende formato "c".
    # o formato default é "n".
    #
    if (FORMATO == "")
        if (CMD == "T")
            FORMATO = "c"
        else
            FORMATO = "n"

    # mensagem de abertura
    if ((FORMATO !~ /^c/) && (CMD == "")) {
        print "Conjugue -- conjugador de verbos para a língua portuguesa"
        print "versão 1.1 (outubro de 99) por Ricardo Ueda Karpischek"
        print "envie correções, críticas ou sugestões para ueda@ime.usp.br."
        print ""
        print "Use por sua própria conta e risco."
        print ""
        print "Tanto o programa quanto o banco de verbos que o acompanha"
        print "são distribuídos sob os termos da licença GNU GPL. Isso"
        print "significa que podem ser livremente copiados e que trabalhos"
        print "derivados devem também ser disponibilizados através dessa"
        print "mesma licença."
        print ""
        print "\"?\" exibe um pequeno guia de utilização."
        print "\"n\" exibe algumas notas importantes."
        print ""
        #print "A atual versão não é capaz de conjugar os verbos conter"
        #print "haver, seguir, conseguir, perseguir e engulir, progredir,"
        #print "agredir, transgredir, prevenir e denegrir. Ela também não"
        #print "trata as formas abundantes, além de outros prováveis problemas."
        #print ""
    }

    # inicializa as flags e estruturas
    fim = 0
    inicializa_tm()
    pr["a"] = pr["e"] = pr["i"] = pr["o"] = ""
    novos = (NOVOS == "") ? ENVIRON["HOME"] "/.conjugue-novos" : NOVOS

    # carregamento do banco
    if ((FORMATO !~ /^c/) && (CMD == "")) {
        print "aguarde o término da leitura do banco..."
    }
    carrega_banco((BANCO=="") ? "/usr/pkg/lib/verbos" : BANCO)

    if (FORMATO ~ /^c/)
        PR = ""
    else
        PR = ":"

    # loop principal
    while (fim == 0) {

        # prompt e leitura do comando
        if (FORMATO ~ /^c/)
            ORS = ""
        else
            ORS = " "
        if ((FORMATO !~ /^c/) && (CMD == ""))
            print PR
        ORS = "\n"
        if (CMD != "") {
            $1 = CMD
            fim = 1
        }
        else
            getline;

        # tempos e modos
        if ($1 == "a") {
            print abrevia
        }

        # comando de abandono
        if ($1 == "f") {
            fim = 1;
        }

        # conjuga o verbo dado
        if (length($1) > 1) {

            # conjuga o verbo
            if ($1 in V)
                conjugue_todos($1)

            else if (substr($1,length($1),1) != "r")
                print "# Não sou capaz de conjugar " $1

            else {
                print "# " $1 " não consta do banco de verbos"
                if (novos != "")
                    print $1 >>novos
                conjugue_todos($1)
            }
        }

        # notas sobre o programa
        if ($1 == "n") {
            print notas
        }

        # lista dos verbos
        if ($1 == "V") {
            for (i in V) print i
        }

        # conjuga todos os verbos conhecidos
        if ($1 == "T") {
            for (i in V) {
                conjugue_todos(i)
            }
        }

        # lista dos comandos disponíveis
        if ($1 == "?") {
            print "a: exibe as abreviações"
            print "<verbo>: conjuga o verbo dado"
            print "f: abandona"
            print "n: exibe algumas notas importantes"
        }
    }
}
