Avatar billede hemmelig_ninja Nybegynder
26. marts 2003 - 09:40 Der er 11 kommentarer og
1 løsning

Noob søger forbedring af program

vi er to nybegyndere der har lavet en simpel regnemaskine. Den kan ikke ret meget, og vi har en fornemmelse af at koden er temmelig grim og besværlig. Vi har bare ikke rigtig flere ideer til hvordan man kan gøre det bedre.

Hvis en venlig sjæl har tænkt sig at kigge dette igennem og komme med et svar, bedes han/hun give kommentarer til ændringerne, da hele ideen med oplægget er, at vi skal lære noget af svaret.

//---------------------------------------------------------------------------
#include <iostream.h>
#include <conio.h>
#include <vcl.h>

void main()
{
        char c_valg='+', c_rstk[30], c_tal[30],c_enkelt;
        int i_fejl=0, i_talok=0, i_talto=0;
        int i_taeller=0, i_t=0, i_pt=0, i_mt=0, i_gt=0, i_dt=0, i_i=0;
        float fl_sum=0, fl_tal=0;
        while(c_valg!='q')
        {
                i_fejl=0;
                gotoxy(25,8);
                cout<<    "Velkommen til RegneMaks!";
                gotoxy(25,9);
                cout<<  "Fremtidens regnemaskine!";
                gotoxy(25,10);
                cout<<  "Brug
    • [/] til at regne";
    •                 gotoxy(25,11);
                    cout<<  "Brug [n] for reset og [q] for quit";
                if (i_taeller==0)
                {
                        gotoxy(25,12);
                    cout<<  "Skriv et regnestykke, f.eks 1+5:";
                        gotoxy(25,17);
                    cin>>c_rstk;
                        gotoxy(25,17);
                        for (i_i=0;c_rstk[i_i]!='\0';i_i++)
                    {
                        c_enkelt=c_rstk[i_i];
                                if (i_talto==1 && c_enkelt!= '\0')
                                {
                                        if (isdigit(c_enkelt) || c_enkelt=='.')
                                        {
                                                c_tal[i_t]=c_enkelt;
                                                i_t++;
                                        }
                                }
                                if (isdigit(c_enkelt) || c_enkelt=='.')
                        {
                                        i_talok=1;
                                }
                        else
                        {
                                        if (i_talok==0)
                                        {
                                    i_fejl++;
                                        }
                                        else
                                        {
                                                c_valg=c_enkelt;
                                                i_talto=1;
                                        }

                        }
                        }
                    if (i_fejl==0)
                    {
                        fl_sum=atof(c_rstk);
                                fl_tal=atof(c_tal);
                    }
                }
                else
                {
                        gotoxy(25,12);
                        cout<<    "Regn videre, f.eks *2:";
                        gotoxy(25,15);
                        cout<<  "="<<fl_sum;
                        gotoxy(25,17);
                        cin>>c_valg;
                        gotoxy(25,18);
                        if (c_valg!='q' && c_valg!='n')
                        {
                                i_talok=0;
                                cin>>c_tal;
                                for (i_i=0;c_rstk[i_i]!='\0';i_i++)
                            {
                                c_enkelt=c_rstk[i_i];
                                if (isdigit(c_enkelt) || c_enkelt=='.')
                                {
                                        i_talok=1;
                                        }
                                else
                                        {
                                                if (i_talok>1)
                                        {
                                            i_fejl++;
                                        }
                                        }
                            }
                            if (i_fejl==0)
                            {
                                fl_tal=atof(c_tal);
                            }
                        }
                }
                i_taeller=1;
                i_talok=0;
                clrscr();
                gotoxy(25,14);
                if (i_fejl==0)
                {
                    switch (c_valg)
                    {
                            case '+':
                            {
                                cout<<fl_sum<<"+"<<fl_tal;
                                fl_sum=fl_sum+fl_tal;
                                        i_pt++;
                                    break;
                            }
                            case '-':
                            {
                                cout<<fl_sum<<"-"<<fl_tal;
                                fl_sum=fl_sum-fl_tal;
                                        i_mt++;
                                break;
                            }
                            case '*':
                            {
                                cout<<fl_sum<<"*"<<fl_tal;
                                fl_sum=fl_sum*fl_tal;
                                        i_gt++;
                                break;
                            }
                            case '/':
                            {
                                    if (fl_sum!=0)
                                    {
                                            cout<<fl_sum<<"/"<<fl_tal;
                                            fl_sum=fl_sum/fl_tal;
                                                i_dt++;
                                    }
                                    else
                                    {
                                            cout<<"Du kan ikke dele med 0";
                                        }
                                    break;
                            }
                            case 'n':
                            {
                                        c_valg='+';
                                        c_enkelt='0';
                                        i_talok=0;
                                        i_talto=0;
                                        i_i=0;
                                        i_t=0;
                                    i_taeller=0;
                                        c_rstk[1]='\0';
                                        c_tal[1]='\0';
                                        fl_sum=0;
                                        fl_tal=0;
                                    break;
                            }
                            default :
                            {
                                    cout<<    "Ugyldig indtastning, TRY AGAIN!.";
                                    break;
                            }
                }
            }
            else
            {
                gotoxy(25,14);
                cout<<    "Du har lavet en indtastningsfejl, TRY AGAIN!";
            }
        }
}

tak fordi du kiggede det igennem :)
Avatar billede arne_v Ekspert
26. marts 2003 - 10:16 #1
Umiddelbart ser det faktisk rimeligt OK ud.

Det er noget meget vanskeligt overskueligt kode. Men jeg tror faktisk
ikke at det er p.g.a. dårlig kode men snarere p.g.a. forkert valg
af design og teknologi.

1)  Den bedste løsning ville være at droppe manuel svanning og parsning
    og erstatte det med lex/flex og yacc/bison.

    Med de værktøjer kan man så nemt som ingenting lave en
    regnemaskine som kan umådeligt megte mere end denne.

    For 15 år siden kom Bison dokumentation faktisk med et lille eksempel
    på en regnemaskine. Den er der sikkert stadig.

2)  Alternativt bør I omstrukturere jeres kode til:
      - scanne input linie og dele op i tal og operatorer
      - konvertere det fra infix til postfix
      - kalkulere det via en stak

Hvis I vil have links til det ene eller det andet, så kan jeg godt prøv
at finde noget.
Avatar billede segmose Nybegynder
26. marts 2003 - 10:16 #2
Det hedder

int main()

ellers kunne man jo tro i var VC programmører.

Flere kommentarer.

Opdel i under functioner, main har her opnået en længde der ville være passende for opdeling.

Opstilling er personlig stil og derfor åben for discussion:
Tom linie mellem de enkelte kode grupper, hos mig bliver det ofte lige før kommentarer for ny handling der skal påbegyndes.
Navngivning af variable behøver I virkelig at lav type_ foran alle variable.
Variable der kun bruges inden for én 'if' burde defineres der, giver performance i C++ da man så ikke behøver at køre contructor hvis den ikke bruges.
Placering af '{' og '}' er religion, I sætter dem som Bjarne og jeg sætter dem (næsten) som K&R2, indrykningen fortæller i forvejen at det er en ny blok.

Så en struktur som:
if (noget)
{
  a = z + 1;
}
else
{
  b = q + 3;
}

mener jeg skal skrives (ignorer her at det kunne skrives helt uden '{'er):

if (noget) {
  a = z + 1;
} else {
  b = q + 3;
}
Avatar billede hemmelig_ninja Nybegynder
26. marts 2003 - 10:23 #3
Øøøm...jeg tror gerne vi vil have links.
Vi er som sagt lige startet på c++, og har ikke den ringeste ide om hvad flere af de ting du skriver er.

Nu kommer vi lige med en række ord i dit svar vi ikke helt forstod:
lex/flex, yacc/bison, svanning/parsning, infix/postfix.

Links er velkomne!
Håber du vil bære over med os.
Hvis du giver nogle gode links og et par svar til, skal vi nok sende dig points'ne :)
Avatar billede arne_v Ekspert
26. marts 2003 - 10:25 #4
tyrk-fejl: scanning ike svanning
Avatar billede arne_v Ekspert
26. marts 2003 - 10:27 #5
ideen i en scanner generator er at man skriver
syntax for heltal, decimaltal etc. i et bestemt format
og så genererer scanner generatoren C/C++ kode der kan
scanne for de pågældende

ideen i en parser generator er at man skriver
Avatar billede arne_v Ekspert
26. marts 2003 - 10:28 #6
[fortsat]

syntax for udtryk og og så genererer parser generatoren
C/C++ kode der parser de tokens der bliver returneret fra scanneren.

Det lyder kompliceret men det er faktisk ret simpelt.
Avatar billede arne_v Ekspert
26. marts 2003 - 10:30 #7
infix = operatorer mellem operander
infix = operatorer efter operander

2 + 3 er infix
2 3 + er postfis

[gamle HP lommeregnere kører postfix]

pointen viser sig når der kommer paranteser:

2 3 + 3 4 + * er langt nemmere at beregne end (2 + 3) * (3 + 4)
Avatar billede arne_v Ekspert
26. marts 2003 - 10:32 #8
Der er rigtigt meget god info om alle problem-stillingerne på:
  http://www.gnu.org/manual/bison-1.35/html_node/
Avatar billede arne_v Ekspert
26. marts 2003 - 10:34 #9
For et eksemple på hvor nemt det er når man har fået strukturen på plads
hop direkte til:
  http://www.gnu.org/manual/bison-1.35/html_node/Infix-Calc.html#Infix%20Calc

Man kan tilføje nye features på 1 minut !
Avatar billede hemmelig_ninja Nybegynder
26. marts 2003 - 10:35 #10
Ok...Vi skal altså til at skrive et program der kan skrive kode selv?
Du skriver den skal generere kode...og det tror jeg ikke lige vi er klar til.
Tak for dit svar, men det lyder en anelse for kompliceret til os.

Ang. segmoses svar, så vil det efter vores mening ikke være hensigtsmessigt at definere variabler i ifsætningerne, når det hele ligger i en while-løkke. Det er en naturlig ting at gøre hvis det ligger i funktioner, men det har vi ikke lige fået lavet endnu.
mht. udseende af kode, så er det nu engang den måde vi bedst kan lide det, men det er jo en smagssag.
Uanset, så tak for kritikken :)
Avatar billede arne_v Ekspert
26. marts 2003 - 10:48 #11
Nej. I skriver en input-fil og så kører i et program (som I kan downloade)
der genererer C/C++ kode som I integrerer i jeres applikation.

Kompliceret ? Lidt ja ! Men måske umagen værd.
Avatar billede olennert Nybegynder
26. marts 2003 - 11:41 #12
Og hvis man vænner sig til at bruge flex, bison og den slags fra starten, så går det også meget nemmere når man en gang skal lave noget lidt mere komplekst.

Hvis man er en C++ haj, så kan man også kigge på Spirit, http://www.boost.org/libs/spirit/index.html. Det kræver at man ved noget om templates, og at man ved hvad en EBNF grammatik er. Disclaimer: Jeg har endnu ikke haft brug for Spirit, så jeg har kun læst om den, ikke selv brugt den. Jeg synes den ser *rigtig* spændende ud.
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester