#!/usr/bin/awk -f
#

#
# Notas importantes
#
BEGIN {
notas = "\
1. Conjugue 1.1 presta-se basicamente para gerar um dicionrio\n\
para ser usado em verificadores ortogrficos. Por isso, os tempos\n\
compostos no so considerados.\n\
\n\
2. O programa chama de irregulares alguns verbos que os\n\
gramticos consideram regulares, e vice-versa. Na medida do\n\
possvel tentaremos sanar essas diferenas (ou ao menos\n\
precis-las) nas prximas verses.\n\
\n\
3. O programa conjugar qualquer verbo no pronominal da lngua\n\
portuguesa, mesmo os que no constam do banco. O paradigma,\n\
quando no  conhecido,  deduzido heuristicamente. No disponho\n\
de exemplos em que a heurstica falha, mas no deve ser difcil\n\
conseguir alguns.\n\
\n\
4. Todas as vezes em que voc tentar conjugar um verbo que no\n\
consta no banco, ele ser concatenado ao arquivo\n\
$HOME/.conjugue-novos (o programa *no* acrescenta o contedo\n\
desse arquivo ao banco quando o banco  carregado logo aps o\n\
disparo do programa)."
}

#
# Notas sobre a implementao
# ---------------------------
#
# Os verbos conhecidos pelo programa so 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 particpio (separador ":").
#
# No primeiro caso, o verbo  flexionado segundo os paradigmas
# regulares. No segundo tambm, 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 particpio).
#
#
# faltam:
# -------
#
# conjugao de verbos pronominais
# suporte para formas abundantes (particpios ok)
# leitura da lista de verbos novos aps o carregamento do banco
#

#
# Lista de tempos e modos
#
BEGIN {
abrevia = "\
FN - formas nominais: infinitivo, gerndio e particpio\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 pretrito 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 conjugao da lista. Retorna
# "R" em caso afirmativo, ou "" caso contrrio (isso  uma reminiscncia
# histrica).
#
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 funo recebe o radical e a conjugao como primeiro
# e segundo parmetros, e classifica o tipo de alterao
# do radical atribuindo-lhe um cdigo numrico.
#
# Por exemplo: se a ltima vogal de um radical for "o" (como
# em "dorm+ir"), ento o cdigo zero associado a esse radical
# indica que essa vogal deve ser trocada por "u" (como em
# "durm+a").
#
# Um mesmo cdigo pode ser utilizado para referir vrias
# transformaes diferentes, desde que a vogal inicial e a
# vogal resultante ocorram como tais uma nica vez sob esse
# cdigo (em outras palavras, cada cdigo deve definir uma
# bijeo).
#
# Para incluir uma nova substituio de vogais sob um cdigo j
# existente, basta adicionar o teste contendo as duas vogais,
# usando como exemplo as transformaes j relacionadas.
#
# Se no for possvel incluir a substituio sob um cdigo j
# existente, ser necessrio criar um novo cdigo. Atualmente
# s se podem usar como cdigos os dgitos decimais (0-9),
# sendo que os dgitos de 0 a 6 (inclusive) esto em uso.
#
# Em qualquer caso,  necessrio incluir a substituio
# inversa na rotina "desnormaliza". Se isso no for feito,
# a mensagem "vogal v invlida para regra n e radical r"
# ser exibida.
#
# Note que a acentuao grfica precisa ser considerada como
# substituio de vogal (proibir > probe).
#
function normaliza(r,c,t,i,j,k,l,v,w,m,n,x,y,u,pi,ri,pk,rk) {

    # quebra a conjugao nas vrias pessoas
    n = split(c,t,":")

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

    # obtm em i a posio 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 alterao do radical
    # dentro dos casos conhecidos. A conjugao  ento alterada
    # da forma
    #     "radical alterado" "sufixo"
    # para a forma
    #     "radical" "sufixo" "cdigo"
    #
    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  > probe),
        # e verifique se se obtm 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 > vo), ou
        #     de u para  (saudar > sado),
        # e verifique se se obtm 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 obtm 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 > apio)
        # e verifique se se obtm 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 > ho)
        # e verifique se se obtm 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 obtm 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 obtm o radical, desconsiderada a ltima letra (ouvir > oua).
        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 no normalizada: w=" w ", y=" y " (" r ":" t[j] ")"
    
        # concatena em c a nova forma da conjugao da pessoa corrente
        c = c ((j>1) ? ":" : "") t[j]
    }

    return(c)
}

#
# desnormaliza um radical, isto , aplica a regra inversa segundo
# as definies da rotina de normalizao. Recebe em r o radical e
# em f o cdigo da transformao. Veja a documentao da funo
# "normaliza" para detalhes.
#
function desnormaliza(r,f,i,v) {

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

        # obtm em i a posio 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 " invlida 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 " invlida 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

        # obtm em ltima vogal do radical reduzido e sua posio
        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 " invlida 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 " invlida 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 " invlida 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 " invlida para regra " f " e radical " r
        }
    }
    return(r)
}

#
# Fatora a conjugao pelo radical, indicando para cada pessoa
# a terminao e a correo do radical, se houver.
#
function fatora_prefixos(verbo,lista,t,mpc,i,R,D,l,lf,j,n,c) {

    # transforma o mpc numa funo 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 ") no resolvido"
    }

    # constri 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 conjugao do verbo, cria um modelo que permite
# aplicar a mesma conjugao 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 recm-lida
        ++l

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

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

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

                # concluda 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 "ocorrncia mltipla de " $1
                        }
                        else
                            V[$1] = paradigma
                        ++m
                    }
                    else {
                        print "conjugue: erro na linha " l " do banco"
                        print $0 " no  verbo"
                    }

                # concluda 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 conjugao  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 so
# 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) {

    # Obteno da raiz e da vogal temtica
    l = length(verbo)
    r = substr(verbo,1,l-2)
    vt = substr(verbo,l-1,1)

    # Obteno do paradigma regular
    cpr = V[pr[vt]]

    # O verbo conta com uma lista especfica 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
            }
        }

        # obtm regras especficas do paradigma
        esp = V[p[1]]
    }

    # Correo do regular pelo especfico
    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]

    # Adio das formas alternativas do particpio
    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
            # enclticas. Note que aqui s so tratados verbos
            # irregulares. De fato, o caso regular  tratado
            # no br.aff pela flag C. A documentao da flag C
            # no br.aff contm muitas informaes adicionais.
            #

            # formas enclticas dos tempos compostos
            if (vt == "a")
                print r ""
            else if (vt == "e")
                print r ""
            else if (vt == "o")
                print r ""

            # formas enclticas da primeira do plural, vrios 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 no  capaz de gerar as conjugaes 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 == "abraar") || (p[1] == "abraar"))
                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 debugao (exibe a regra de formao)
    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 "   gerndio: " cs[2]
        print "   particpio: " 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 pretrito 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 "   no " 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 Pretrito 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"] = "ns"
    P["5"] = "vs"
    P["6"] = "eles"
}

#
# O programa comea 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 lngua portuguesa"
        print "verso 1.1 (outubro de 99) por Ricardo Ueda Karpischek"
        print "envie correes, crticas ou sugestes para ueda@ime.usp.br."
        print ""
        print "Use por sua prpria conta e risco."
        print ""
        print "Tanto o programa quanto o banco de verbos que o acompanha"
        print "so distribudos sob os termos da licena GNU GPL. Isso"
        print "significa que podem ser livremente copiados e que trabalhos"
        print "derivados devem tambm ser disponibilizados atravs dessa"
        print "mesma licena."
        print ""
        print "\"?\" exibe um pequeno guia de utilizao."
        print "\"n\" exibe algumas notas importantes."
        print ""
        #print "A atual verso no  capaz de conjugar os verbos conter"
        #print "haver, seguir, conseguir, perseguir e engulir, progredir,"
        #print "agredir, transgredir, prevenir e denegrir. Ela tambm no"
        #print "trata as formas abundantes, alm de outros provveis 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 trmino da leitura do banco..."
    }
    carrega_banco((BANCO=="") ? "/usr/local/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 "# No sou capaz de conjugar " $1

            else {
                print "# " $1 " no 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 disponveis
        if ($1 == "?") {
            print "a: exibe as abreviaes"
            print "<verbo>: conjuga o verbo dado"
            print "f: abandona"
            print "n: exibe algumas notas importantes"
        }
    }
}
