I am about to start a project of something like simple calculator completely in c and I was wondering how would I allow the user to create variables during the run time of the program, this variable could be a number or complex number or even a matrix or a
one approach was to store the type of the variable, its name and its size and value in a temporary text file and retrieve it whenever needed, is there any better approach. I hope if I could declare real variables during runtime in c
OK, you are going to need three basic modules:
N.B. I haven't had the time to actually compile these examples, hopefully I didn't make too many mistakes.
Parser. This module takes a user entered input, tokenizes it and insures that the entered expression conforms to the grammer.
Interpreter. This module takes the output of the parser and preforms the computation.
Environment. This module manages the state of the computation.
Lets start with the environment, here is what we need (or at least what I would implement). First here are the design considerations the I would use for the environment:
We will only deal with variables
We will only allow 300 variables
All variables will have global scope
Rebinding a variable will overwrite the old binding
Now, lets define the following structure:
typedef struct st
{
char* tokenName;
int type;
union
{
int iVal;
float fVal;
} val;
} tableEntry, * ptableEntry;
tableEntry symbolTable[300];
and now for some functions:
a. init(tableEntry*) -- this function initialized the environment, i.e. sets all values in the symbol table to some, predefined empty state.
b. addValue(tableEntry*, name, value) -- this function takes a pointer to the environment and adds a new entry to the environment.
c. int lookupValue(tableEntry*, name) -- this function takes a pointer to the environment and sees if the token name has been defined in it. Already, we see a problem, we are allowing for both integers and floating point numbers but would like a single lookup functions, so we probably need some sort of variant type or figure out some way to return different types.
d. updateValue(tableEntry*, name, value) -- this function takes a pointer to the environment and updates an existing value. This raises an unaddressed specification, what should updateValue do if the token is not found? Personally I would just add the value, but it up to you as the designer of the calculator on what to do.
This should do for a start for the environment.
Now lets turn to the interpreter for a bit. For this let suppose that the parser emits the abstract syntax tree in prefix form. For example:
the statement x=3 would be emitted as = x 3
the statement z = 4 + 5 would be emitted as = z + 4 5
OK, the trick here is we don't really emit 3, but rather a token that contains more information about what is being passed around.
A possible implementation of a token might be:
typedef struct tok
{
int tokType;
char* tokVal;
} token, * ptoken;
Also lets have the following enumeration:
enum {EMPTY=0, ID, VAL, EQ, PLUS, SUB, MULT, DIV, LPAREN, RPAREN};
so, with this the simplified statement = x 3, would actually be the following
structures:
{EQ, null} {ID, "x"} {VAL, "3"}
OK, so the interpreter in pseudo-code would look like (assuming that the above is presented to the interpreter as a list).
while list not empty
token <-- head(list) /* this returns the first token as well as removing it from the list */
switch (token.tokType)
{
....
case EQ: /* handling assignment */
token <--- head(list)
name = token.name
token <--- head(list)
val = atoi(token.tokVal)
addValue(env*, name, val);
break;
case ID:
name = token.name
val = lookupValue(env*, name)
....
}
Please, be advise that the actual format of the above code will in all probability need to be modified to deal with other constructs, it is just a notional example!
Now it's your turn -- take a stab and show us what you've come up with.
Later
T.
You can not declare new variables at runtime in C as such.
For what you want you could make a list of structs for each type you want to support. Each struct then contains the name of the variable and its value. Declaring a variable will add a new struct to the list.
I'm assuming you were thinking about an interaction with you calculator that might look something like this:
> myCalc
mc> x=5
mc> 5
mc> 3*x
mc> 15
mc> quit
>
Where myCalc is the name of your program, and the mc>prompt shows interaction with the calculator, where the use enters a statement and the calculator displays the result of the statement.
Now, consider the first statement x=5, we need to parse it and determine if it is a valid according to the grammar you are using. Assuming it is, you then need to evaluate the statement, which for sake of discussion has
the abstract syntax tree (AST) ASMT(x,VAL(5)). ASMT and VAL are notional operators.
Now, I would take this as adding a new binding for x into the current environment. Exactly how this environment looks depends on what you are willing to allow, so for now lets assume you are just allowing variable assignment. A simple associative array would work here, where the key is the variable name and the data would be the value.
Now consider the next statement 3*x, after parsing we can assume the AST for the expression is TIMES(3, ID(x)). Now on evaluation of this, or interpreter would first need to handle the ID(x) part which would be looking up the value of x in the environment, which is 5.
After the above, the AST would look like TIMES(3,5) which would be directly evaluated as 15.
N.B. I am being fairly loose with what how AST would be represented and how it would be evaluated by the interpreter. I'm trying to give a flavour of what to do, not full low-level implementation details.
hope this helps (a bit),
T
Related
I am taking a MATLAB programming class and we are currently working on a project which uses a database called Project2 of several structs of airline flight data (all 1 x N). One exercise requires us to create a function that identifies the number of flights segments (housed in the flights struct) that used the Boeing 737-800 aircraft. Below I have included the code for the function I created (NOTE: The format of the first line is such that was dictated in the instructions and must remain that way). Although this function seems to work and be free of bugs, it consistently returns a result of 0 and I cannot figure out why. Can anyone help? Suggestions for fixing the problem and/or cleaning up the code would be greatly appreciated!
function total = Problem2 (flights, aircraft, airlines, airports)
load Project2
id=findAircraftID (aircraft, Boeing 737-800)
seg=0;
for jj = 1:length(flights)
if (strcmp (flights(1,jj).aircraft_id, id))
seg=seg+1
end
end
fprintf ('A total of %d flight segments used the Boeing 737-800 aircraft.\n', seg)
end
function id=findAircraftID (aircraft, AircraftName)
id=0;
for ii=1:length(aircraft)
if (strcmp (aircraft(1,ii).name, AircraftName))
id=ii;
return;
end
end
end
Why are you using strcmp to compare integers? Is aircraft_id a string? Perhaps you can cast id from an int to a string if so. Or better yet you can just use isequal(a,b):
if isequal(flights(1,jj).aircraft_id, id)
seg=seg+1;
end
Also see other methods at Octave/MATLAB: How to compare structs for equality?
Also (or alternatively if that's not the issue) you're iterating through your second function and setting id several times, but only the last value goes into the first function. Take a closer look at your for loops to see whether you need to wrap them, store id as an array rather than a single integer, etc.
Never mind I see that your code could work if aircraft names are unique. strcmp should work in that case - but perhaps step through and check that you aren't having issues because of capitalization, spaces, etc.
Usually when you want to find an element in an array that matches a condition, you use something like
bWhenAis3 = B(A == 3);
To find the value of B when A is 3. This can return a vector of multiple values, and is usually much faster than an explicit loop.
In your code, aircraftID is an integer because it's returned by findAircraftID which returns ii. You cannot compare this with a string! You need to compare like types.
Admitted, this question is not very interesting, but since the warnings in the sas-log can be very helpful sometimes I'd like to know what is going on here.
Consider the following minimal example. In step0 we created a dataset. In step 1 we want to copy the value of some variable in step0 to step1 but we forgot the correct name of the variable (or we remember correctly but someone changed it when we were away.) I write two versions of step1 named step1a and step1b.
Data step0;
Dog = 1;
run;
Data step1a;
value = cat;
run;
Data step1b;
array animals cat;
value = animals[1];
run;
Needless to say both version of step1 produce the same dataset, in this case an empty dataset with variables 'value' and 'cat'.
However: when running step1 in the way step1a is written, the SASlog will warn us that something is wrong:
NOTE: Variable cat is uninitialized.
We can go back to our code, notice that what we think was a cat was actually a dog all along, see the error of our ways and produce the correct dataset we had in mind.
When on the other hand running step1 in the way step1b is written, the SASlog will act as if everything is perfectly fine and we can go out singing and dancing in the street only to find out years later that the value of dog is lost forever.
So the question is: why does SAS think in the second case that no warning is needed?
That's because you HAVE initialized the variable in the third example, via the array declaration. When you declare an array, any variables not already existing are initialized to Numeric missing, unless you either specify $ in the array definition (in which case they are character missing (length 8)), or you specify an initialized value.
This is a multiple part question. Firstly my input file will look like this:
category Shoes brand:char[50],cost:int
category Shirts brand:char[20],cost:int
My questions are:
a.) How do I break up the line at : only after the category name? Shoes or Shirts in these cases.
b.) How would I write my Bison parser such that I would be determining the variables (eg. char[30]) of the struct that would hold the information for each line?
If these questions seem too localized, I'd appreciate it if I could be guided to some resources that could help me do the same
There are far too many missing details. For instance, can "int" be used as a category name? How do you plan to store the data you parse?
Still, an initial sketch would be something like this for the parser:
%token CATEGORY "category"
EQ "="
COLON ":"
COMMA ","
LBRA "["
RBRA "]"
INT "int"
CHAR "char"
ID
NATURAL
;
%%
categories:
category
| categories category
;
category:
"category" ID fields
;
fields:
field
| fields "," field
;
field:
ID ":" type
;
type:
"char"
| "int"
| type "[" NATURAL "]"
;
and this for the scanner:
%%
"category" return CATEGORY;
"=" return EQ;
":" return COLON;
"," return COMMA;
"[" return LBRA;
"]" return RBRA;
"int" return INT;
"char" return CHAR;
[a-zA-Z]+ return ID;
[0-9]+ return NATURAL;
[ \n\t]+ continue;
(b.) I'm not sure I understand your question correctly. I assume you want to parse each entry in the input file and store the info in a struct. Category and Brand would be strings and cost would be an int. You want to know beforehand, the length of the strings, so you can assign a variable to hold the parsed value (such as char[20]).
Why not use C++ strings? Then you don't have to declare the length . Example here.
If you must use C, you can just have a char * and allocate the string on heap using malloc.
This page has a reasonable, simple example that can be a guide to what you're trying to do. A complete general procedure for writing a flex/bison parser is:
Decide what the tokens are, write a regex and choose an identifier for each (as #akim has done in his flex/bison code).
Write a LALR(1) Context Free Grammar for the "legal" input you're trying to parse. #akim has given you a leg up on this one.
Design a target data structure to hold the parser result. This is the key thing missing in your post. If you are just trying to compute a single integer size, then you're done. If you need to pass more detail on for further processing, you'll want some kind of record/enumeration/list structure, which is normally called an abstract syntax tree or AST even though it's often not really a tree.
Implement the AST (if necessary) data structure including constructor functions like CATEGORY_NODE make_category(enum category_e cat);. These constructors will be called by the parser.
Implement the tokens in a flex scanner program file with no action code.
Implement the CFG in the bison parser program file with no action code.
Build a test frame and a test suite and test that the scanner and parser read legal inputs and reject bad ones. So far the program does nothing else. This is where #akim's code is now.
Decide what data must be associated with each token, if any. For example, an unsigned number's value would be its magnitude returned from the scanner as an unsigned int. An identifier's value will be a string. But a bracket [ has no value at all. Use these types to create the bison %union directive to accept values from the scanner. Add these as <union_field> tags to the respective %token directives. See the example for the #union used there, which has two token value types.
Fix the flex scanner by adding an #include "foo.tab.h" at the top and adding action code to return the correct token value for the respective tokens. At this point everything should compile and run again, but still do nothing. Again refer to the example.
Now implement data handing in the parser. You'll be using the dollar $n and $$ directives and adding <union_field> type tags to grammar nonterminals to move data among the grammar rules and finally calls to the constructors for your AST structure to build the structure as the input is read (or to increment the integer if that's all it is). This is where experience and deeper knowledge of LALR parsers is helpful. The later examples in the Bison documentation are another reference for this part. If you hit roadblocks, come back with specific questions.
Run the tests again and print the resulting AST in a form you can verify. XML works well for this.
Now I'm sure someone will observe that this fully general approach is overkill for what you've asked so far. It depends .Your current input is so simple that you could probably hand-write a little ad hoc parser more quickly, not using flex or bison at all.
However if the program you're writing is likely to be in use for a while and to change over time, having all the machinery of a general parser in place at the beginning can make life much easier. Thinking about program input as a real language rather than just raw data can lead you to create functionality that otherwise would never have occurred to you.
I'm trying to give a semantic value to a list of comma-separated values. In fact, I have defined the reduction rules for bison using
commasv : exp
| commasv "," exp
where exp its a number or a variable or a function pointer or, also, a commasv token with its respective syntax and semantic rules. The type of exp is double so the type of commasv must be double.
The thing is that I want to store the list in order to use it, for example, on a function call. For instance
h = create_object()
compute_list(h,1,cos(3.14159))
will give the expected result of a certain compute_list function.
As basis bison file I've used mfcalc example from the bison manual and I replaced the yylex function by other one generated using flex. By now I can do things like
pi = 3.14159
sin(pi)
ln(exp(5))
with the modified version of yylex function with flex but I want use the comma-separated values with function calls, lists creation and more.
Thanks for your answers.
Then create a list to store the results in. Instead of having the result of the commasv rule return an actual value, have it return the list head.
In general, as soon as you get a somewhat moderately advanced grammar (like it incorporating things like lists), you can no longer really use values to represent the parsing, but have to go over to some sort of abstract syntax tree.
Does anyone know how I could implement I predicate doing what this one does but without "findall"?
Thank you a lot.
domains
oferta = rebaixat ; normal
element = string
list = element*
database
producte (string, integer, oferta)
predicates
nondeterm reduced2(list)
clauses
producte("Enciam",2,rebaixat).
producte("Peix",5,normal).
producte("Llet",1,rebaixat).
producte("Formatge",5,normal).
reduced2(Vals):-
findall(Val, producte(Val,_,rebaixat),Vals).
Goal
write("Amb findall"),nl,
reduced2(List).
I don't know much about Visual Prolog, but I will try to give a general answer. It depends on whether you want to find a findall/3 replacement for a specific case or in general, though.
In the specific case, you can use an accumulator. In your case, this would be a list into which the values are added as you find them. Something like:
acc(In, List) :-
... % do something to generate possible next value
... % test if value is already in list In
!,
Out = [Val|In], % adds to the head, but is faster than using append
acc(Out, List).
acc(List, List).
I.e., when you can't find another possible value, you return the list of values that you found. Note that this may be slow if you have to accumulate a lot of values and generating the next possible value is done via backtracking. Also, this will not let you generate duplicates, so it's not an exact replacement for findall/3.
If you want a general replacement for findall/3, where you can specify a goal and a variable or term that will contain the instance to be accumulated, then you won't get around using some sort of non-logical global variable. After finding the next value, you add it to what's been stored in the global variable, and cause backtracking. If generating the next value fails, you retrieve the content of the global variable and return it.