Kalkulator parser C

0

Witam mam za zadanie stworzenie parsera analizującego wyrażenie matematyczne. Jako skaner używam lexa. Dotychczas stworzyłem rozwiazywanie prostych rozwiązań (dodawanie odejmowanie mnożenie dzielenie) z kolejnością wykonywania działań również biorąc pod uwagę nawiasy. Jednak w treści polecenia mam również ująć działania na ułamkach wymiernych.

SKANER:

%{

#include <stdio.h>
#include <stdlib.h>
#include "parser.tab.h"

%}

digit [0-9]
digits {digit}+
plus_op "+"
minus_op "-"
mult_op "*"
div_op "/"
op_bracket "("
cl_bracket ")" 
dec_num {digits}
frac_op "|"
fraction {digits}{frac_op}{digits}

%% 

{dec_num} { yylval = strtol(yytext,NULL,10); return CALKOWITA; }

{fraction} { recturn ULAM; }

{plus_op} { return PLUS; }

{minus_op} { return MINUS; }

{mult_op} { return MNOZ; } 

{div_op} { return DZIEL; }

{op_bracket} { return OTW; }

{cl_bracket} { return ZAM; }

\n { return yytext[0]; } 


%%

Parser:

%{
	#include <stdio.h>
	#include <string.h>
	int yyerror();
	int numExpressions = 0;
%} 

%token LICZBA CALKOWITA PLUS MINUS MNOZ DZIEL OTW ZAM ULAM

%%

 calosc : 
	| calosc wiersz
	;  
wiersz : '\n'
	| wyrazenie '\n' { printf("wartosc = %d\n",$1); ++numExpressions; }
	

 wyrazenie : wyrazenie PLUS skladnik { $$ = $1 + $3; } 
	 | wyrazenie MINUS skladnik { $$ = $1 - $3; } 
	 | skladnik { $$ = $1; }  
	 ;  


 skladnik : skladnik MNOZ czynnik { $$ = $1 * $3; }  
	 | skladnik DZIEL czynnik { $$ = $1 / $3; } 
	 | czynnik
	 ; 
 
 czynnik : liczba { $$ = $1; }
	| OTW wyrazenie ZAM { $$ = $2; } 
 
 
 liczba : CALKOWITA { $$ = $1; } 
	| MINUS CALKOWITA {$$ = -$2; } 
	;

 %%  
 int main() {
	 printf("Poczatek skanowania ...\n");
	 yyparse(); 
	 printf("\nKoniec skanowania\n"); 
	 printf("\tprzeczytano %d poprawnych wyrazen\n\n",numExpressions);
	 return 0;  
 }
 
 
 int yyerror(char *s) { 
	printf("Blad: %s\n", s);
 }
0

do tego służy Odwrotna Notacja Polska: https://pl.wikipedia.org/wiki/Odwrotna_notacja_polska
I masz właśnie ten algorytm zaimplementować.

0

Potrzebowałbym porady co do przedstawienia ułamka jako symboli, nie mam totalnie pojęcia w jaki sposób mógłbym to zrobić, dotychczasowy kod nie za dużo mi pomaga.

0

Potrzebujesz tokenizer, czyli program, który z wejścia: "2|3 + 1|4 * 2", stworzy listę tokenów, np.: ["(2, 3)", "+", "(1, 4)", "*", "(2, 1)"]. Możesz bardziej rozbudować strukturę Token, jak tutaj:
https://craftinginterpreters.com/scanning.html
A potem, rzeczywiście najprościej, będzie do ONP:
https://runestone.academy/runestone/books/published/pythonds/BasicDS/InfixPrefixandPostfixExpressions.html

0

Inaczej (niż @lion137) mówiąc potrzebujesz analizatora leksykalnego, i w (dwuosobowej) rodzinie yacc'a jest to lex.
Wsad do lex'a podajesz, co z nim dalej robisz?

Analiza leksykalna (w mojej opinii) jest łatwiejsza niż syntaktyczna i ręczne zakodowanie też nie jest złe.

1

Widzę że porady tu są totalnie z czapy (w stylu użyj leksera (tokenizera) gdy już używasz leksera) więc postaram się wysilić szara komórki i coś sobie przypomnieć z yacc.
Po pierwsze nie zmieniaj leksera. Jest on dobry. Ułamek to conajmniej trzy tokeny (dzielna, dzielnik i znak dzielenia) więc jest dobrze.
Po drugie w parserze musisz zlikwidować operacje dzielenia i zastąpić ją operacją tworzenia liczby wymiernej czyli linia

| skladnik DZIEL czynnik { $$ = $1 / $3; }

zamienia się w linię

| skladnik DZIEL czynnik { $$ = createRationalNumber($1,$3); }

Gdzie RationalNumber jest strukturą dwóch liczb całkowitych.
Pociąga to za sobą kolejne zmiany. Teraz na stosie wartości nie możesz mieć prostych liczb całkowitych, tylko unie które są albo liczbą całkowitą, albo liczbą wymierną (alternatywą jest zamiana liczb całkowitych na wymierne z dzielnikiem równym 1).
Oczywiście skomplikuje to wszystkie wyrażenia matematyczne. np jeśli będziesz chciał dodać dwie liczby to będziesz musiał sprawdzić czy są one obie całkowite (i dodać je w sposób całkowity), czy obie wymierne (i dodać je w sposób wymierny) czy jedna jest wymierna a druga całkowita (i i wtedy trzeba przekonwertować całkowitą na wymierną). Oczywiście po każdej operacji dochodzi jeszcze problem skracania ułamków.
Na oko zgaduję że masz dopiero 10% potrzebnego kodu.

1 użytkowników online, w tym zalogowanych: 0, gości: 1