Calculating min/max with more than two parameters - calculator

As a Homework we got a basic calculator which can only do + operations and we have to implement more functions. We had to implement the bracket operator, sign operators and min max functions. One of the last tasks is to expand the min/max function to calculate min/max with more than only two parameters and thats the task where I'm currently stuck.
My current calc.l lex file:
%{
extern int yylval;
extern int sym[];
extern int yyerror(char *s);
#include "y.tab.h"
%}
%%
[a-z] {
yylval = *yytext - 'a';
return VARIABLE;
}
[0-9]+ {
yylval = atoi(yytext);
return INTEGER;
}
[(),] { return *yytext; }
":=" return ASSIGN;
"+" return PLUS;
"-" return MINUS;
"/" return DIVIDE;
"%" return MODULO;
"*" return TIMES;
"<" return SMAS;
"<=" return SMGAS;
"==" return IS;
"!=" return NOTIS;
">=" return BGGAS;
">" return BGAS;
"min" return MIN;
"max" return MAX;
"\n" return NEWLINE;
[ \t] ;
. yyerror("Invalid character");
%%
int yywrap() {
return 1;
}
My current calc.y yacc file:
%{
#include <stdio.h>
int sym[26];
int yylex();
int yyerror(char *s);
%}
%token VARIABLE ASSIGN INTEGER NEWLINE
%left PLUS
%left TIMES
%left MINUS
%left DIVIDE
%left MODULO
%left UMINUS
%left UPLUS
%left SMAS SMGAS IS NOTIS BGAS BGGAS
%left MIN MAX
%%
program: program statement
|
;
statement: expr NEWLINE
{ printf("%d\n", $1); }
| VARIABLE ASSIGN expr NEWLINE
{ sym[$1] = $3; }
;
expr: INTEGER { $$ = $1; }
| VARIABLE { $$ = sym[$1]; }
| expr PLUS expr { $$ = $1 + $3; }
| expr TIMES expr { $$ = $1 * $3; }
| expr MINUS expr { $$ = $1 - $3; }
| expr DIVIDE expr { $$ = $1 / $3; }
| expr MODULO expr { $$ = $1 % $3; }
| '(' expr ')' { $$ = $2; }
| MINUS expr %prec UMINUS { $$ = -$2; }
| PLUS expr %prec UPLUS { $$ = $2; }
| expr SMAS expr { $$ = $1 < $3; }
| expr SMGAS expr { $$ = $1 <= $3; }
| expr IS expr { $$ = $1 == $3; }
| expr NOTIS expr { $$ = $1 != $3; }
| expr BGGAS expr { $$ = $1 >= $3; }
| expr BGAS expr { $$ = $1 > $3; }
| MIN '(' expr ',' expr ')' { if ($3 < $5){ $$ = $3; } else if ($3 > $5){ $$ = $5; }; }
| MAX '(' expr ',' expr ')' { if ($3 > $5){ $$ = $3; } else if ($3 < $5){ $$ = $5; }; }
;
%%
int yyerror(char *s) {
fprintf(stderr, "%s\n", s);
return 0;
}
int main() {
yyparse();
return 0;
}
I think one solution would be to seperate each value with an , in the min/max function and calculate it and then give it back to the min/max function, but I'm not sure how to implement it. The only solution I could think of is rather complex. Since the project shouldn't be that complex I think I'm missing an easy way to do it.
min(5, 6) returns 5 as it should, and the expected way how it should work is (min 6, 7, 3) and return 3 and you can expend it to an infinite number of parameters.
Does any of you have an Idea?
Thanks!

You need max(x,y) and max(x,y,z,q..).
One possible solution is (... x , z ...) repeatable so you will need few rules for that. Note var, it is use to determine what operation we need.
expr ',' expr { if(var==1){$$=$1>$3?$1:$3;}else{$$=$1<$3?$1:$3;}; }
'(' expr ')' { $$ = $2;}
MAX expr { $$ = $2;}
MAX expr { $$ = $2;}
In your *.l file you need external variable (let's call it var)
extern int var.
Add also a redex rule for max and min, which will set our variable to 1 or 0:
min { op =0;}
max { op =1;}
Where 1 is MAX and MIN is 0.
This is done in .l file because we want to set the var first before me make the operations.
If you do it in .y file, the var will be set after the operations.
Add the variable to your *.y file too (int var =0).
In .y file you MAX and MIN should be %tokens. Plus, add , with %right on first/second place (you can use COMMA instead ,). Otherwise if you have ..4,5*5,.. if will first compare and then it will multiply it.

AIUI you should handle an arbitrary number of arguments to min/max. The standard way to do that would be
first to move the argument list into a separate rule, e.g. arg_list: expr ',' expr ; and make that return a list(-like object). The (sub)rules for min/max then calculate upon that returned list.
Second, make that arg_list rule handle 1 to n entries by making it recursive, analogous to the expr rule itself. The min/max rules then still have to calculate upon a list, just have to assume an arbitrary length >= 1, instead of length == 2.

Related

How to generate arbitrary instances of a language given its concrete syntax in Rascal?

Given the concrete syntax of a language, I would like to define a function "instance" with signature str (type[&T]) that could be called with the reified type of the syntax and return a valid instance of the language.
For example, with this syntax:
lexical IntegerLiteral = [0-9]+;
start syntax Exp
= IntegerLiteral
| bracket "(" Exp ")"
> left Exp "*" Exp
> left Exp "+" Exp
;
A valid return of instance(#Exp) could be "1+(2*3)".
The reified type of a concrete syntax definition does contain information about the productions, but I am not sure if this approach is better than a dedicated data structure. Any pointers of how could I implement it?
The most natural thing is to use the Tree data-type from the ParseTree module in the standard library. It is the format that the parser produces, but you can also use it yourself. To get a string from the tree, simply print it in a string like so:
str s = "<myTree>";
A relatively complete random tree generator can be found here: https://github.com/cwi-swat/drambiguity/blob/master/src/GenerateTrees.rsc
The core of the implementation is this:
Tree randomChar(range(int min, int max)) = char(arbInt(max + 1 - min) + min);
Tree randomTree(type[Tree] gr)
= randomTree(gr.symbol, 0, toMap({ <s, p> | s <- gr.definitions, /Production p:prod(_,_,_) <- gr.definitions[s]}));
Tree randomTree(\char-class(list[CharRange] ranges), int rec, map[Symbol, set[Production]] _)
= randomChar(ranges[arbInt(size(ranges))]);
default Tree randomTree(Symbol sort, int rec, map[Symbol, set[Production]] gr) {
p = randomAlt(sort, gr[sort], rec);
return appl(p, [randomTree(delabel(s), rec + 1, gr) | s <- p.symbols]);
}
default Production randomAlt(Symbol sort, set[Production] alts, int rec) {
int w(Production p) = rec > 100 ? p.weight * p.weight : p.weight;
int total(set[Production] ps) = (1 | it + w(p) | Production p <- ps);
r = arbInt(total(alts));
count = 0;
for (Production p <- alts) {
count += w(p);
if (count >= r) {
return p;
}
}
throw "could not select a production for <sort> from <alts>";
}
Tree randomChar(range(int min, int max)) = char(arbInt(max + 1 - min) + min);
It is a simple recursive function which randomly selects productions from a reified grammar.
The trick towards termination lies in the weight of each rule. This is computed a priori, such that every rule has its own weight in the random selection. We take care to give the set of rules that lead to termination at least 50% chance of being selected (as opposed to the recursive rules) (code here: https://github.com/cwi-swat/drambiguity/blob/master/src/Termination.rsc)
Grammar terminationWeights(Grammar g) {
deps = dependencies(g.rules);
weights = ();
recProds = {p | /p:prod(s,[*_,t,*_],_) := g, <delabel(t), delabel(s)> in deps};
for (nt <- g.rules) {
prods = {p | /p:prod(_,_,_) := g.rules[nt]};
count = size(prods);
recCount = size(prods & recProds);
notRecCount = size(prods - recProds);
// at least 50% of the weight should go to non-recursive rules if they exist
notRecWeight = notRecCount != 0 ? (count * 10) / (2 * notRecCount) : 0;
recWeight = recCount != 0 ? (count * 10) / (2 * recCount) : 0;
weights += (p : p in recProds ? recWeight : notRecWeight | p <- prods);
}
return visit (g) {
case p:prod(_, _, _) => p[weight=weights[p]]
}
}
#memo
rel[Symbol,Symbol] dependencies(map[Symbol, Production] gr)
= {<delabel(from),delabel(to)> | /prod(Symbol from,[_*,Symbol to,_*],_) := gr}+;
Note that this randomTree algorithm will not terminate on grammars that are not "productive" (i.e. they have only a rule like syntax E = E;
Also it can generate trees that are filtered by disambiguation rules. So you can check this by running the parser on a generated string and check for parse errors. Also it can generated ambiguous strings.
By the way, this code was inspired by the PhD thesis of Naveneetha Vasudevan of King's College, London.

How do you convert or Abbreviate Numbers in Autohotkey(AHK)? (posting answers made by the autohotkey discord group)

I needed to convert numbers in Autohotkey for a game I'm making and some members of the Autohotkey Discord Group were able to help me out.
In particular vieira and andreas#Nasa:~$ sudo -i each came up with a working solution.
vieira
print(GetFormatedNum(1234567890))
print(GetFormatedNum(1234567))
print(GetFormatedNum(1234))
print(GetFormatedNum(12))
GetFormatedNum(num) {
for k, v in [{12:"T"},{9:"B"},{6:"M"},{3:"K"}] {
for i, j in v
if (num >= (10**i))
return % SubStr(num/(10**i),1,5) j
}
return num
}
1.234B
1.234M
1.234K
12
andreas#Nasa:~$ sudo -i
InputBox, num, Num Input, Input the number you want to be converted
if num is not Integer
return
MsgBox, % "Num is: " . num
MsgBox, % "this is converted: " . Converter.Convert(num)
return
class Converter {
static 1 := "k"
static 2 := "M"
static 3 := "G"
static 4 := "T"
Convert(int){
if int is not Integer
Throw, Exception("Illegal type", -1)
size := Floor(Floor(Log(int)) / 3)
if(size == 0)
return int
While(true){
Try {
ending := this[size]
break
}
Catch e {
if(e.Message == "key to great")
size--
}
}
return, Round(Floor(int / (10 ** (size * 3 - 1)))/ 10, 1) . Ending
}
__Get(vKey){
if(vKey > 0)
Throw, Exception("key to great")
return, 0
}
}
I am immensely grateful to each of them and to BoBo and elmodo7 for helping me this morning.
andreas#Nasa:~$ sudo -i
InputBox, num, Num Input, Input the number you want to be converted
if num is not Integer
return
MsgBox, % "Num is: " . num
MsgBox, % "this is converted: " . Converter.Convert(num)
return
class Converter {
static 1 := "k"
static 2 := "M"
static 3 := "B"
static 4 := "T"
Convert(int){
if int is not Integer
Throw, Exception("Illegal type", -1)
size := Floor(Floor(Log(int)) / 3)
if(size == 0)
return int
While(true){
Try {
ending := this[size]
break
}
Catch e {
if(e.Message == "key to great")
size--
}
}
return, Round(Floor(int / (10 ** (size * 3 - 1)))/ 10, 1) . Ending
}
__Get(vKey){
if(vKey > 0)
Throw, Exception("key to great")
return, 0
}
}
edit: personally all this is beyond me but this solution is his final answer.
conv := new Converter()
Loop, 10 {
Random, num, 0, 2147483647
num := num * 1000000
Print("Num is: " . num . " and this is converted: " . conv.Convert(num))
}
return
class Converter {
__New(){
this.endingChars := new EndChars("k", "M", "G", "T") ; put the endings for each step here in the correct order...
}
Convert(int){
if int is not Integer
Throw, Exception("Illegal type", -1)
size := Floor(Floor(Log(int)) / 3)
if(size == 0)
return int
While(size > 0){
Try {
ending := this.endingChars[size]
break
}
Catch e {
size--
}
}
return, Round(Floor(int / (10 ** (size * 3 - 1)))/ 10, 1) . ending
}
}
class EndChars {
__New(EndingChars*){
for k, i in EndingChars
this[k] := i
}
__Get(vKey){
if(vKey > 0)
Throw, Exception("key to great")
return, 0
}
}
and you can just add the next character in line to EndChars

How to convert integer to hex notation?

Using: Firebird 2.5.3
In a stored procedure (PSQL), converting a number from hex notation to decimal notation is done easily:
DECLARE VARIABLE I INTEGER;
BEGIN
I = CAST('0x0FFFE' AS INTEGER); -- I will have the value 65534
How can the reverse be achieved? ie. Convert from decimal notation to hex notation?
Short of using a UDF (which would mean using an external library file), the solution is to write a stored procedure to accomplish this:
SET TERM ^^ ;
CREATE PROCEDURE INTTOHEX (
INPUTNUMBER BigInt)
returns (
OUTPUTNUMBER VarChar(8))
AS
DECLARE VARIABLE Q BigInt;
DECLARE VARIABLE R BigInt;
DECLARE VARIABLE T BigInt;
DECLARE VARIABLE H VARCHAR(1);
DECLARE VARIABLE S VARCHAR(6);
begin
/* Max input value allowed is: 4294967295 */
S = 'ABCDEF';
Q = 1;
OUTPUTNUMBER = '';
T = INPUTNUMBER;
WHILE (Q <> 0) DO
BEGIN
Q = T / 16;
R = MOD(T, 16);
T = Q;
IF (R > 9) THEN
H = SUBSTRING(S FROM (R-9) FOR 1);
ELSE
H = R;
OUTPUTNUMBER = H || OUTPUTNUMBER ;
END
SUSPEND;
end ^^
SET TERM ; ^^
You can call this stored procedure from standard SQL or another stored procedure like this:
For example:
SELECT OUTPUTNUMBER FROM INTTOHEX(65534);
just did a short firebird function,
could handle bigger number,
maybe could help someone
CREATE OR ALTER FUNCTION INT64TOHEX (
C BIGINT)
RETURNS VARCHAR(32)
AS
DECLARE VARIABLE IREM INTEGER;
DECLARE VARIABLE HEX VARCHAR(32);
BEGIN
IREM = MOD(C, 0XFF);
HEX = '';
WHILE (IREM > 0) DO
BEGIN
HEX = SUBSTRING('0123456789abcdef' FROM BIN_SHR(BIN_AND(C, 0XFF), 4) + 1 FOR 1) || SUBSTRING('0123456789abcdef' FROM BIN_AND(BIN_AND(C, 0XFF), 15) + 1 FOR 1) || HEX;
C = BIN_SHR(C, 8);
IREM = MOD(C, 0XFF);
END
RETURN TRIM(HEX);
END

Adding abs(x) and sqrt(x) functions to flex/bison calculator

I have to make a calculator in flex/bison for a lab in class and I have to add functionality to compute square roots or absolute values in they put in sqrt(x) or abs(x). I imported the math library and I got the caculator to work if the COMMAND FOR IT CONSIST OF ONE CHARACTER. Here's what I mean:
expr:
......
| '(' expr ')' { $$ = fabs($2); } //for abs
| '[' expr ']' {$$ = sqrt($2); } //for sqrt
.......
now, this works fine and if i put in (-2) i get 2, or [4] = 2. The problem is clearly, i need to make it so the command is abs(x) and sqrt(x). If I switch the code to say
| "abs(" expr ')' { $$ = fabs($2); } //for abs
| "sqrt" expr ']' {$$ = sqrt($2); } //for sqrt
this doesn't work because it sees the a then b, and tries to do something with that. This is likely because my calculator also supports assigning variable values (like x=2), so it thinks there should be an operator between a and b. I unfortunately have no idea how to fix this. I would appreciate any help.
Here's my code if that helps:
hexcalc.y
%{
#include <stdio.h>
#include <math.h>
#include <stdlib.h> // often required
// A simple error message to move things along
void yyerror(const char *msg)
{
printf("ERROR(PARSER): %s\n", msg);
}
// Storage for variables: yes Virginia, only 26 variables possible in this langu$
long variables[26];
%}
%union {
float nvalue;
int ivalue;
int varindex;
}
%token <nvalue> NUMBER
%token <ivalue> INT
%token <varindex> NAME
%type <nvalue> expr
%type <nvalue> term
%type <nvalue> varOrNum
%%
statementList : statement '\n'
| statement '\n' statementList
;
statement : NAME '=' expr { variables[$1] = $3; }
| expr { printf("RESULT: %f\n", $1); }
;
expr: expr '+' term { $$ = $1 + $3; }
| expr '-' term { $$ = $1 - $3; }
| '-' term { $$ = 0 - $2; }
| "abs(" expr ')' { $$ = $2; }
| "sqrt(" expr ')' { $$ = sqrt($2); }
| expr '/' term { $$ = $1 / $3; }
| term { $$ = $1; }
;
term : term '*' varOrNum { $$ = $1 * $3; }
| varOrNum { $$ = $1; }
;
varOrNum : NUMBER { $$ = $1; }
| NAME { $$ = variables[$1]; }
;
%%
main() {
int i;
for (i=0; i<26; i++) variables[i] = 0;
yyparse();
}
hexcalc.l
%{
#include <stdlib.h>
#include <math.h>
#include "hexcalc.h"
#define BASE 10
char* endptr;
%}
%%
[a-z] { yylval.varindex = yytext[0] - 'a'; $
}
[0-9]+ { yylval.nvalue = atof(yytext);
return NUMBER;
}
[0-9]+"."[0-9]+?|"."[0-9]+? {yylval.nvalue = atof(yytext);
return NUMBER;
}
[ \t] ;
\n|. { return yytext[0];
}
%%
int yywrap() {
return 1;
}
You need to recognize multicharacter names in the lexer as single tokens and then use them in your grammar. The easy way is to just add them to your lexer:
abs { return ABS; }
sqrt { return SQRT; }
Then you can add to your parser:
%token ABS SQRT
%%
expr: ABS '(' expr ')' { $$ = fabs($3); }
| SQRT '(' expr ')' { $$ = sqrt($3); }
You need to create rules in your .l file for "abs" and "sqrt"; declare the tokens they will each return via %token; and use those token names in the grammar rules: ABS "(" expr ")" : ...
You should have a look at Bison's documentation where a more scalable solution for predefined functions is given (using a symbol table).
http://www.gnu.org/software/bison/manual/html_node/Multi_002dfunction-Calc.html

lex program: error: expected ';', ',' or ')' before numeric constant?

I've checked other similar posts but I think I just need a second set of eyes. This file is for the lex Unix utility.
I created a makefile and this is the error I receive:
gcc -g -c lex.yy.c
cxref.l:57: error: expected ‘;’, ‘,’ or ‘)’ before numeric constant
make: *** [lex.yy.o] Error 1
Line 57 is just inside the void inserID() function near the top.
Here is the code:
%{
#include <stdio.h>
#include <string.h>
char identifier[1000][82];
char linesFound[100][100];
void insertId(char*, int);
int i = 0;
int lineNum = 1;
%}
%x comment
%s str
%%
"/*" BEGIN(comment);
<comment>[^*\n]* /* eat anything that's not a '*' */
<comment>"*"+[^*/\n]* /* eat up '*'s not followed by '/'s */
<comment>\n ++lineNum;
<comment>"*"+"/" BEGIN(INITIAL);
"\n" ++lineNum;
auto ;
break ;
case ;
char ;
continue ;
default ;
do ;
double ;
else ;
extern ;
float ;
for ;
goto ;
if ;
int ;
long ;
register ;
return ;
short ;
sizeof ;
static ;
struct ;
switch ;
typedef ;
union ;
unsigned ;
void ;
while ;
[*]?[a-zA-Z][a-zA-Z0-9_]* insertId(yytext, lineNum);
[^a-zA-Z0-9_]+ ;
[0-9]+ ;
%%
void insertId(char* str, int nLine)
{
char num[2];
sprintf ( num, "%d", nLine);
int iter;
for(iter = 0; iter <= i; iter++)
{
if ( strcmp(identifier[iter], str) == 0 )
{
strcat( linesFound[iter], ", " );
strcat( linesFound[iter], num );
return;
}
}
strcpy( identifier[i], str );
strcat( identifier[i], ": " );
strcpy( linesFound[i], num );
i++;
}
Your problem is:
%s str
There is a reason that it's normal to write condition names in CAPS: it makes them look like macros, which is exactly what they are.
So
void insertId(char* str, int nLine)
get macro expanded to something like:
void insertId(char* 2, int nLine)
and the compiler complains that 2 is not really expected at that point in the declaration.