Get the calkulator to use braqets the right way!

Hi!
I want to make this code so i can make calculations with brackets, like 3(2)-1 =
Now, my calculator just takes 3-1 when i enter the calculation over. Can someone help me with that? :slight_smile:

(Don't mind the comments, they are in Norwegian)
(erlikknapp means equals button)

#include <Keypad.h> //for å kunne bruke Keypaden
#include <LiquidCrystal.h> //for å kunne bruke LCD skjermen

LiquidCrystal lcd(3, 4, 5, 6, 7, 8); //LCDpinnene

//Hvor mange rader og kolonner det er:
const byte RAD = 4; // fire rader
const byte KOL = 4; // fire kolonner

//Her definerer jeg keypad oppsettet:
char knapper [RAD] [KOL] = {
{'1', '2', '3', '+'},
{'4', '5', '6', '-'},
{'7', '8', '9', '*'},
{'(', '0', ')', '/'}
};

//Hvilke pinner rader og kolonner er koblet til:
byte radPins[RAD] = {9 ,10 ,11 ,12 }; //Koblet til Rad 1,2,3 og 4 i riktig rekkefølge, så de riktige tegnene kommer opp når man trykker

byte kolPins[KOL] = {A3 ,A2 ,A1 ,A0 }; //Koblet til Kolonne 1,2,3 og 4.

//Lager keypaden:
Keypad myKeypad = Keypad( makeKeymap(knapper), radPins, kolPins, RAD, KOL );

//Beskrivelse av variabler:
boolean valOnePresent = false;
boolean next = false;
boolean final = false;
String num1, num2; //Gjør så to tall kan regnes med
int ans; //forkortelse for answer/svar
char op; // forkortelse for operation
int erlikknapp = A4; //Deffinerer erlikknappen
boolean lastButton = LOW;
boolean currentButton = LOW;
boolean sum = false;
int temp_read; //brukes for å lese erlikpinne
int X = A5;

boolean debounce(boolean last){ //For å få erlikknappen til å fungere når den skal
boolean current = digitalRead(erlikknapp);
if (last != current){
delay(50);
current = digitalRead(erlikknapp);
}
return current; //går tilbake
}

void setup(){
pinMode(erlikknapp, INPUT); //definerer erlikknappen som INPUT
pinMode (X, INPUT); //definerer X som INPUT
lcd.begin(16,2); //Forteller at LCDskjermen skal startes
lcd.setCursor(2,0); //Forteller at operatoren skal begynne å skrive i det øvre venstre hjørnet
lcd.print("Kalkulator av"); //Her velger jeg hva som skal stå på LCDskjermen når den starter opp
lcd.setCursor (0,1);
lcd.print ("Maria Andresen");
delay(5000); //Hvor lenge det skal stå
lcd.clear(); //Blanker ut skjermen så man kan skrive et regnestykke
Serial.begin(9600); //Debug, starter serial monitoren
}

void loop(){
char knapp = myKeypad.getKey(); //Forteller at knappene er på Keypaden

if (knapp != NO_KEY && (knapp=='1'||knapp=='2'||knapp=='3'||knapp=='4'||knapp=='5'||knapp=='6'||knapp=='7'||knapp =='8' || knapp=='9'||knapp=='0' || knapp == '(' || knapp == ')')){ //legger inn alle tallene og parentesene (tok lang til før jeg forsto de måtte være her...
if (valOnePresent != true){
num1 = num1 + knapp; //sier at tall en skal bestemmes av en knapp på Keypaden
int numLength = num1.length();
lcd.setCursor(15 - numLength, 0); //For å lage mellomrom for operatøren i vinduet
lcd.print(num1); //Sier at tallet som trykkes ned skal vises på skjermen
Serial.print("num1: "); //PRINTS LABEL FOR DEBUG
Serial.println(num1); //FOR DEBUG PRINT NUM1 VERDI + NY LINJE
}
else {
num2 = num2 + knapp; //sier at nummer to skal bestemmes av en knapp som trykkes ned på Keypaden
int numLength = num2.length();
lcd.setCursor(15 - numLength, 1); //For å lage mellomrom for operatøren i vinduet
lcd.print(num2); //Sier at tallet som trykkes ned skal vises på skjermen
final = true; //forteller at når tall to er trykket ned, skal det ikke kunne komme en regneoperasjon til.
Serial.print("num2: "); //PRINTS LABEL FOR DEBUG
Serial.println(num2); //FOR DEBUG PRINT NUM2 VERDI + NY LINJE
}
}

else if (valOnePresent == false && knapp != NO_KEY && (knapp == '/' || knapp == '*' || knapp == '-' || knapp == '+')){ //Legger inn alle regnetegnene
if (valOnePresent == false){
valOnePresent = true;
op = knapp; //Sier at det skal bestemmes av en knapp på Keypaden
lcd.setCursor(15,0); //Gjør at operatøren er i høyre hjørne
lcd.print(op); //Sier at tegnet/operasjonen som trykkes ned skal vises på skjermen
Serial.println(op); //Debug print i serial monitoren + ny linje
}
}

if(erlikknapp == HIGH){ //sier at hvis erlikknapp er High, skal svar bli vist.
sum = true;
delay(500); //delay for debounce
}

temp_read = analogRead(A4); //leser den analoge verdien på knappen g konverterer den til digital verdi. ADC
// Fra en verdi mellom 0-1023 til 0-5V
if(temp_read >= 800){ //Hvis verdien på knappen er høyere eller lik 800, skal det i ifløkka gjøres
sum = true; //Gjør at summen skal komme opp
lcd.setCursor(0,1); //visning i nedre venstre hjørte
lcd.print("sum:"); //Sier at tegnet som trykkes ned skal vises på skjermen
Serial.println(temp_read); //Debug, printer temp_read + ny linje
delay(2000); //tiden hvor "sum" skal vises i lcd
}

//Gjør regnestykket:
currentButton = debounce(lastButton); //debounce gjør funksjonen blir sjekket to ganger
//if (lastButton == LOW && currentButton == HIGH){
if(sum == true){
Serial.println("gjennom første if settning"); //debug for å sjekke at hele løkka gås igjennom. Printes i Serial monitoren
//if (final == true && knapp != NO_KEY && knapp == '='){//legger inn =knappen
//if (final == true && knapp != NO_KEY && sum == true){//
Serial.println("gjennom andre if settning"); //debug for å sjekke at hele løkka gås igjennom. Printes i Serial monitoren
if (op == '+'){ //Definerer tegnet som skal leses
ans = num1.toInt() + num2.toInt(); //Gjør så to tall kan legges sammen
}
else if (op == '-'){
ans = num1.toInt() - num2.toInt(); //GJør så et tall kan trekkes fra et annet
}
else if (op == '*'){
ans = num1.toInt() * num2.toInt(); //GJør så et tall kan ganges med et annet
}
else if (op == '/'){
ans = num1.toInt() / num2.toInt(); //Gjør så et tall kan deles på et annet
}

lastButton = currentButton; // setter forrige knapp til
lcd.clear(); //Clearer ut skjermen
lcd.setCursor(15,1); //Operatoren i høyre nedre hjørte
lcd.autoscroll(); //Gjør at den skroller av seg selv
lcd.print(ans); //gjør at den skriver ut svaret
lcd.noAutoscroll(); //GJør at det ikke skrolles av seg selv
sum = false;
Serial.print("ans: "); //printer "ans:" i serial monitoren før svaret
Serial.println(ans); // Debug som printer verdien (svaert) + ny linje
}

X = analogRead(A5); //Deffinerer og leser xknappen
//tømmer skjermen etter svaret er gitt så det går an å skrive et nytt regnestykke:
if ( X >= 800 ){
lcd.clear(); //clearer skjermen for det som står der.
valOnePresent = false;
final = false;
num1 = ""; //tar bort tall 1 (erstattes med det inni "tegnene)
num2 = ""; //tarbort tall 2 (erstattes med det inni "tegnene)
ans = 0; //setter svar=0
op = ' '; // setter operation til ingenting, så det ikke er noe på minnet
lcd.setCursor(0,1); //Operatoren i høyre nedre hjørte
lcd.print("Nullstiller"); //printer "nullstiller" på LCDskjermen
delay(1500); //trenger forsinkelse for å vise tekst før skjermen tømmes
lcd.clear(); //tømmer bildet på lcd
Serial.println("Nullstiller"); //Debugprint som Clear screenverdien + ny linje
}
}

LiquidCrystal lcd(3, 4, 5, 6, 7, 8); //LCDpinnene

Is the smiley Norwegian too ?
Please put the code in code tags to prevent the forum software from mangling it when it is displayed.

Whoops, I'm sorry...

#include <Keypad.h> //for å kunne bruke Keypaden
#include <LiquidCrystal.h> //for å kunne bruke LCD skjermen 

LiquidCrystal lcd(3, 4, 5, 6, 7, 8 ); //LCDpinnene 

//Hvor mange rader og kolonner det er:
const byte RAD = 4; // fire rader
const byte KOL = 4; // fire kolonner

//Her definerer jeg keypad oppsettet:
char knapper [RAD] [KOL] = {
{'1', '2', '3', '+'},
{'4', '5', '6', '-'},
{'7', '8', '9', '*'},
{'(', '0', ')', '/'}
};

//Hvilke pinner rader og kolonner er koblet til:
byte radPins[RAD] = {9 ,10 ,11 ,12 }; //Koblet til Rad 1,2,3 og 4 i riktig rekkefølge, så de riktige tegnene kommer opp når man trykker 

byte kolPins[KOL] = {A3 ,A2 ,A1 ,A0 }; //Koblet til Kolonne 1,2,3 og 4. 

//Lager keypaden:
Keypad myKeypad = Keypad( makeKeymap(knapper), radPins, kolPins, RAD, KOL );

//Beskrivelse av variabler:
boolean valOnePresent = false;
boolean next = false;
boolean final = false;
String num1, num2; //Gjør så to tall kan regnes med 
int ans; //forkortelse for answer/svar
char op; // forkortelse og definisjon for operation 
int erlikknapp = A4; //Deffinerer erlikknappen 
boolean lastButton = LOW; //setter forrige knapp lav
boolean currentButton = LOW; //setter nåværende knapp lav
boolean sum = false; 
int temp_read;   //brukes for å lese erlikpinne
int X = A5; //Definerer at X/clearknappen er koblet til pinne A5

boolean debounce(boolean last){ //For å få erlikknappen til å fungere når den skal
boolean current = digitalRead(erlikknapp);
if (last != current){
delay(50);
current = digitalRead(erlikknapp); 
}
return current; //går tilbake
}


void setup(){
  pinMode(erlikknapp, INPUT); //definerer erlikknappen som INPUT
pinMode (X, INPUT); //definerer X som INPUT
lcd.begin(16,2); //Forteller at LCDskjermen skal startes
lcd.setCursor(2,0); //Forteller at operatoren skal begynne å skrive i det øvre venstre hjørnet
lcd.print("Kalkulator av"); //Her velger jeg hva som skal stå på LCDskjermen når den starter opp
lcd.setCursor (0,1);
lcd.print ("Maria Andresen"); 
delay(5000); //Hvor lenge det skal stå
lcd.clear(); //Blanker ut skjermen så man kan skrive et regnestykke 
Serial.begin(9600); //Debug, starter serial monitoren 
}


void loop(){
char knapp = myKeypad.getKey(); //Forteller at knappene er på Keypaden

if (knapp != NO_KEY && (knapp=='1'||knapp=='2'||knapp=='3'||knapp=='4'||knapp=='5'||knapp=='6'||knapp=='7'||knapp =='8' || knapp=='9'||knapp=='0' || knapp == '(' || knapp == ')')){ //legger inn alle tallene og parentesene (tok lang til før jeg forsto de måtte være her...
if (valOnePresent != true){
num1 = num1 + knapp; //sier at tall en skal bestemmes av en knapp på Keypaden
int numLength = num1.length();
lcd.setCursor(15 - numLength, 0); //For å lage mellomrom for operatøren i vinduet
lcd.print(num1); //Sier at tallet som trykkes ned skal vises på skjermen 
Serial.print("num1: ");         //PRINTS LABEL FOR DEBUG
Serial.println(num1);	//FOR DEBUG PRINT NUM1 VERDI + NY LINJE
}
else {
num2 = num2 + knapp; //sier at nummer to skal bestemmes av en knapp som trykkes ned på Keypaden 
int numLength = num2.length(); 
lcd.setCursor(15 - numLength, 1); //For å lage mellomrom for operatøren i vinduet 
lcd.print(num2); //Sier at tallet som trykkes ned skal vises på skjermen 
final = true; //forteller at når tall to er trykket ned, skal det ikke kunne komme en regneoperasjon til.
Serial.print("num2: ");         //PRINTS LABEL FOR DEBUG
Serial.println(num2);	//FOR DEBUG PRINT NUM2 VERDI + NY LINJE
}
}

else if (valOnePresent == false && knapp != NO_KEY && (knapp == '/' || knapp == '*' || knapp == '-' || knapp == '+')){ //Legger inn alle regnetegnene 
if (valOnePresent == false){
valOnePresent = true;
op = knapp; //Sier at det skal bestemmes av en knapp på Keypaden
lcd.setCursor(15,0); //Gjør at operatøren er i høyre hjørne 
lcd.print(op); //Sier at tegnet/operasjonen som trykkes ned skal vises på skjermen
Serial.println(op);	//Debug print i serial monitoren + ny linje 
}
}

if(erlikknapp == HIGH){ //sier at hvis erlikknapp er High, skal svar bli vist.
sum = true;  
 delay(500);  //delay for debounce
}

temp_read = analogRead(A4);  //leser den analoge verdien på knappen g konverterer den til digital verdi. ADC 
                            // Fra en verdi mellom 0-1023 til 0-5V
if(temp_read >= 800){ //Hvis verdien på knappen er høyere eller lik 800, skal det i ifløkka gjøres
  sum = true; //Gjør at summen skal komme opp
  lcd.setCursor(0,1); //visning i nedre venstre hjørte 
  lcd.print("sum:"); //Sier at tegnet som trykkes ned skal vises på skjermen
  Serial.println(temp_read);	//Debug, printer temp_read + ny linje 
  delay(2000); //tiden hvor "sum" skal vises i lcd
}


//Gjør regnestykket:
currentButton = debounce(lastButton); //debounce gjør funksjonen blir sjekket to ganger
//if (lastButton == LOW && currentButton == HIGH){
if(sum == true){ 
Serial.println("gjennom første if settning"); //debug for å sjekke at hele løkka gås igjennom. Printes i Serial monitoren
//if (final == true && knapp != NO_KEY && knapp == '='){//legger inn =knappen
//if (final == true && knapp != NO_KEY && sum == true){//
Serial.println("gjennom andre if settning"); //debug for å sjekke at hele løkka gås igjennom. Printes i Serial monitoren
if (op == '+'){ //Definerer tegnet som skal leses
ans = num1.toInt() + num2.toInt(); //Gjør så to tall kan legges sammen
}
else if (op == '-'){
ans = num1.toInt() - num2.toInt(); //GJør så et tall kan trekkes fra et annet
}
else if (op == '*'){
ans = num1.toInt() * num2.toInt(); //GJør så et tall kan ganges med et annet
}
else if (op == '/'){ 
ans = num1.toInt() / num2.toInt(); //Gjør så et tall kan deles på et annet
} 


lastButton = currentButton; // setter forrige knapp til 
lcd.clear();  //Clearer ut skjermen
lcd.setCursor(15,1); //Operatoren i høyre nedre hjørte 
lcd.autoscroll(); //Gjør at den skroller av seg selv
lcd.print(ans); //gjør at den skriver ut svaret 
lcd.noAutoscroll(); //GJør at det ikke skrolles av seg selv
sum = false; 
Serial.print("ans: "); //printer "ans:" i serial monitoren før svaret  
Serial.println(ans);	// Debug som printer verdien (svaert) + ny linje
}

X = analogRead(A5); //Deffinerer og leser xknappen 
//tømmer skjermen etter svaret er gitt så det går an å skrive et nytt regnestykke:
if ( X >= 800 ){ 
lcd.clear(); //clearer skjermen for det som står der.
valOnePresent = false;
final = false;
num1 = ""; //tar bort tall 1 (erstattes med det inni "tegnene)
num2 = ""; //tarbort tall 2 (erstattes med det inni "tegnene)
ans = 0; //setter svar=0
op = ' '; // setter operation til ingenting, så det ikke er noe på minnet
lcd.setCursor(0,1); //Operatoren i høyre nedre hjørte 
lcd.print("Nullstiller"); //printer "nullstiller" på LCDskjermen 
delay(1500); //trenger forsinkelse for å vise tekst før skjermen tømmes
lcd.clear(); //tømmer bildet på lcd
Serial.println("Nullstiller");	//Debugprint som Clear screenverdien + ny linje 
}
}

Moderator edit: CODE TAGS

There are two algorithms you can use to parse an expression:

Here is a parser using the shuntyard algorithm and my State machine library

#include <SM.h>

enum op{
  NOP, DIGIT, DP, RP, LP, PLUS, MINUS, MUL, DIV, SOE, EOE};
op op1 = SOE;
op op2;
op opStack[8];//operator stack
byte opTOS;//stack pointer for op stack

int digitV;//holding value of digit

float valStack[8];//value stack
byte valTOS;//value stack pointer
unsigned long intVal;//integer value
unsigned long fracVal;//fractional value
unsigned long divVal = 1;//divior for adjusting fractional value

boolean complete;//result available

SM parse(soe);//start of expression

void setup(){
  Serial.begin(115200);
}//setup()

void loop(){
  //only run when chars are available
  if(Serial.available()) EXEC(parse);
  if(complete){
    Serial.println(valStack[--valTOS]);//result = final stackvalue
    complete = false;
  }//if(complete)
}//loop()

State soe(){
//action
  switch(op1){
  case EOE://end off expression finalise stack 
    while(Serial.available()) Serial.read();//purge buffer
    while(opTOS) calc(opStack[--opTOS]);//finalise calculation
    op1 = SOE;
    complete = true;
    return;//do not read new input char
  case PLUS://operator
  case MINUS:
  case MUL:
  case DIV:
    while(opStack[opTOS-1] >= op1) calc(opStack[--opTOS]);//calculate higher precedence
    opStack[opTOS++] = op1;//push op1
  }//switch(op1)
//transition  
  op1 = (op)tokenize(Serial.read());
  switch(op1){//check new input char
  case DIGIT: 
    return parse.Set(integer);
  case MINUS: 
    return parse.Set(negative);
  case LP:
    return parse.Set(lp);
  default:
    parse.Set(seqErr);
  }//switch(op1)
}//SOE()

State lp(){
//action: push LP on opStack
  opStack[opTOS++] = LP;
//transition
  op1 = (op)tokenize(Serial.read());
  switch(op1){//check new char
  case DIGIT: 
    return parse.Set(integer);
  case MINUS: 
    return parse.Set(negative);
  case LP: 
    break;//no state change
  default: 
    parse.Set(seqErr);
  }//switch(op1)
}//lp()

State negative(){
//action: convert -exp to 0-exp
  valStack[valTOS++] = 0;//push 0 on valstack
  opStack[opTOS++] = MINUS;//
//transition
  op1 = (op)tokenize(Serial.read());
  switch(op1){//check new char
  case DIGIT: 
    return parse.Set(integer);
  case MINUS: 
    break;//no state change
  case LP:
    return parse.Set(lp);
  default: 
    parse.Set(seqErr);
  }//switch(op1)   
}//negative()

State integer(){
//action: update integer part of input value
  intVal = intVal*10+digitV;//update value with new digit 
//transition
  op1 = (op)tokenize(Serial.read());
  switch(op1){
  case RP:
    parse.Set(rp);
    pushV();//value is final
    return;
  case DIGIT: 
    break;//no state change
  case DP: 
    return parse.Set(fraction);
  case PLUS: 
  case MINUS: 
  case MUL: 
  case DIV:
  case EOE:
    parse.Set(soe);
    pushV();//value is final
    return;
  default: 
    parse.Set(seqErr);
  }//switch(op1)
}//integer()

State fraction(){
//action: update fraction part of input value
  if(op1 == DIGIT){//first call op1 == DP
    fracVal = fracVal*10+digitV;//update value with new digit
    divVal *= 10;//update divisor  
  }//if(digit)
//transition
  op1 = (op)tokenize(Serial.read());
  switch(op1){//check new input char
  case RP:
    parse.Set(rp);
    pushV();//value is final
    return;
  case DIGIT: 
    break;//no state change
  case PLUS: 
  case MINUS: 
  case MUL: 
  case DIV:
  case EOE:
    parse.Set(soe);
    pushV();//value is final
    return;
  default: 
    parse.Set(seqErr);
  }//switch(op1) 
}//fraction()

State rp(){
//action: do calculations until LP
  while(opTOS&&((op2 = opStack[--opTOS]) != LP)) calc(op2);
//trasition
  op1 = (op)tokenize(Serial.read());
  switch(op1){
  case RP:
    break;//no state change
  case PLUS: 
  case MINUS: 
  case MUL: 
  case DIV:
  case EOE:
    return parse.Set(soe);
  default: 
    parse.Set(seqErr);
  }//switch(op1) 
}//rp()

State seqErr(){
  Serial.println("seqErr: ");
  op1 = (op)tokenize(Serial.read());
  while(Serial.available()) Serial.read();//purge buffer
  op1 = SOE;
  parse.Set(soe);  
}//seqErr()

int tokenize(char ch){
  switch(ch){
  case '.': 
    return DP;
  case ')': 
    return RP;
  case '+': 
    return PLUS;
  case '-': 
    return MINUS;
  case '*': 
    return MUL;
  case '/': 
    return DIV;
  case '(': 
    return LP;
  case '\r':
    return EOE;
  case '0': 
  case '1':
  case '2':
  case '3':
  case '4':
  case '5':
  case '6':
  case '7':
  case '8':
  case '9': 
    digitV = ch-'0';
    return DIGIT;
  }//switch(ch)
  return NOP;
}//tokenize()

void pushV(){//push input value on valStack and reset value
  if(valTOS < sizeof(valStack)/sizeof(valStack[0]))//check valStack
    valStack[valTOS++] = intVal+(float)fracVal/divVal;//push value
  else 
    op1 = NOP;//error
  intVal = 0;//reset value
  fracVal = 0;//reset value
  divVal = 1;//reset value
}//pushV()

void calc(int op){
  float value = valStack[--valTOS];//pop value
  switch(op){//do calculation
  case PLUS:
    valStack[valTOS-1] += value; 
    break;
  case MINUS:
    valStack[valTOS-1] -= value; 
    break;
  case MUL:
    valStack[valTOS-1] *= value; 
    break;
  case DIV:
    valStack[valTOS-1] /= value; 
    break;
  }//switch(operator)
}//calc()

moore expression parser state diagram.png

knapp=='1'||knapp=='2'||knapp=='3'||knapp=='4'||knapp=='5'||knapp=='6'||knapp=='7'||knapp =='8' || knapp=='9'||knapp=='0'

You know, the really cool thing about the ASCII table is that it is NOT random. The digits 0 to 9 are in consecutive positions. So, that whole mess could be shortened to:

knapp >= '0' && knapp <= '0'

So, that whole mess could be shortened to:

knapp >= '0' && knapp <= '0'

PaulS obviously means:

knapp >= '0' && knapp <= '9'

Anyway, they made a function for that:

if (isdigit (knapp) || <other tests> )

PaulS obviously means:

What idiot decided that the 0 key went next to the 9 key?

PaulS:
What idiot decided that the 0 key went next to the 9 key?

Not a C programmer, right? Or 0 would be on the left.