How to get a variable value from a Custom Indicator in MQL4 in Expert Adviser? - indicator

If I have an indicator ( myIndi ) which generates a variable ( Var1 ), how can I access the Var1 from an EA, please?
I've tried iCustom() but not getting the results.

iCustom() is a primary interface between EA and Custom Indicators
There is no reason, why would a call to iCustom() not return a value, given the myIndi compilation was successful and the constructed Custom Indicator is principally correct in its internal workings ( do not hesistate to post the MCVE-code example to prove or dis-prove this ).
Next step: publish an update of your post, to include an MCVE-code so as to review the root-cause of the actual state of such call:
retVal = iCustom( _Symbol, PERIOD_CURRENT, "myIndi",
<p1>,
<p2>,
...,
<id#>,
<shift>
);
Formal interface is a bit tricky, but a ( self-)discipline can help a lot:
The following method is robust for both EA-side and Indicator-side teams to smoothly and safely share evolving ideas and for maintaining all the versions of iCustom() EA-side call-interface clean and safe plus creating the calling-interface a way more readable ( with #define-ed human-readable names for meaningful and coherent line#-identifications ).
These sections are maintained by the Custom Indicator developers, during the whole life-cycle of a Custom Indicator and EA-teams just #include these as a self-explanatory template once any version is being used inside EA.
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! <<_MAINTAINED_SECTION_>>.START
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//!!! -------------------------------------------||||||||||||||||||||||||||||||||||||||||||| POSITIONAL ORDINAL-NUMBERED CALLING INTERFACE ||||||||||||||||||||| all iCustom() call MUST BE REVISED ____________________________ !!!
//--- indicator parameters -------------------------------------------||||||||||||||||||||||||||||||||||||||||||| POSITIONAL ORDINAL-NUMBERED CALLING INTERFACE ||||||||||||||||||||| all iCustom() call MUST BE REVISED ____________________________ !!!
//!!! -------------------------------------------||||||||||||||||||||||||||||||||||||||||||| POSITIONAL ORDINAL-NUMBERED CALLING INTERFACE ||||||||||||||||||||| all iCustom() call MUST BE REVISED ____________________________ !!!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
#define XYZ_CUSTOM_INDICATOR_NAME "an_XYZ_<fileName_w/o_.MQ4>" // the Custom Indicator fileName
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//--- input parameters -------------------------------------------------------- iCustom( ) CALL INTERFACE
input int nBARs_period = 18;
extern double MUL_SIGMA = 0;
sinput ENUM_APPLIED_PRICE aPriceTYPE = PRICE_CLOSE;
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
/* = iCustom( _Symbol, PERIOD_CURRENT, XYZ_CUSTOM_INDICATOR_NAME, // |-> iCustom INDICATOR NAME
XYZ_nBARs_period, // |-> input1 nBARs_period
XYZ_MUL_SIGMA, // |-> input2 MUL_SIGMA
XYZ_PRICE_TYPE, // |-> input3 aPriceTYPE from: ENUM_APPLIED_PRICE
XYZ_<_VALUE_>_BUFFER_ID, // |-> line# --------------------------------------------from: { 0: Val1 == Buffer0[] | 1: Buffer1[] | ... }
aShift // |-> [aShift]-aTimeDOMAIN-offset of a Val1[] to return
); //
*/
#define XYZ_Val1_BUFFER_ID 0 // <---- <Val1>[]
#define XYZ_Val2_BUFFER_ID 1
#define XYZ_Val3_BUFFER_ID 2
#define XYZ_Val4_BUFFER_ID 3
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//!!! -------------------------------------------||||||||||||||||||||||||||||||||||||||||||| POSITIONAL ORDINAL-NUMBERED CALLING INTERFACE ||||||||||||||||||||| all iCustom() call MUST BE REVISED ____________________________ !!!
//--- indicator parameters -------------------------------------------||||||||||||||||||||||||||||||||||||||||||| POSITIONAL ORDINAL-NUMBERED CALLING INTERFACE ||||||||||||||||||||| all iCustom() call MUST BE REVISED ____________________________ !!!
//!!! -------------------------------------------||||||||||||||||||||||||||||||||||||||||||| POSITIONAL ORDINAL-NUMBERED CALLING INTERFACE ||||||||||||||||||||| all iCustom() call MUST BE REVISED ____________________________ !!!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! <<_MAINTAINED_SECTION_>>.END
Any other approaches were historically proven to be more painfull or more risky.
Using GlobalVariable* call(s) is not a robust use-case for this problem-domain, as many side-effects are to be expected and such code-value-integration is prone to stop working without EA-being able to detect such ( semantic ) failure.
Using a Custom Indicator logic "inside" EA is possible, but at a cost of a complete re-design of the logic, as EA code-execution unit behaves way different from the Custom Indicator code-execution unit in the MetaTrader4 Terminal code-execution environment. It is fair to note, that due to MQL4-language-( and Terminal )-revisions, it makes sense just for an HFT-grade Project, or for extremely latency-sensitive implementations to carefully decide cons and pros before going into this direction.

There are two ways:
- let this variable be a buffer and access that buffer and position through iCustom();
- write such variable as GlobalVariablesOfClientTerminal and read it as GV.
Also possible to move the indicator's logic inside the EA, in such case you will be able to access that parameter directly, but that is usually not so easy.

use global variables to transfer the var values between EAs and indicators.

Related

what does $1 means in yacc, and how can I get its value

I want to complete a parsing about varlist declaration,
like varlist:id comma varlist|id.
At this time, I need to set up a list about var.
So I write this code:
varlist: id comma varlist{ createtnode($1.idcontext);}
|id{createtnode($1.idcontext);};
But I find $1.idcontext is not that idcontext I want which should be this id token's idcontext.
Now, $1.idcontext is this sentence 'varlist'. Without the code action, this grammar works correctly.
typedef struct{
int* TC;
int* FC;
}boolcode;
typedef struct {
char* idcontext;
int constvalue;
int chain;
boolcode ftentry;
}includes;
/* Value type. */
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef struct{
int classify;
includes unique;
} YYSTYPE;
# define YYSTYPE_IS_TRIVIAL 1
# define YYSTYPE_IS_DECLARED 1
#endif
VARList: IDENcode COMMA VARList{
if(YYDEBUG)
{printf("6\n");
printf("%s\n",$1.idcontext);
}
varlistnode* newvar=malloc(sizeof(varlistnode));
newvar->varname=$1.idcontext;
newvar->value=0;
newvar->next=NULL;
mynotes->next=newvar;
mynotes=mynotes->next;
}|IDENcode{
if(YYDEBUG)
{printf("7\n");printf("%s\n",$1.idcontext);}
varlistnode* newvar=malloc(sizeof(varlistnode));
newvar->varname=$1.idcontext;
newvar->value=0;
newvar->next=NULL;
mynotes->next=newvar;
mynotes=mynotes->next;
};
The words wait recognize:
a,b,c,d
The result of printf() function:
7
d:
6
c,d:
6
b,c,d:
6
a,b,c,d:enter code here
The real problem in this program is not visible in this question because the bug is in your lexical scanner.
You haven't included the flex file in the question, but it's reasonable to guess that it contains something like this:
[[:alpha:]_][[:alnum:]_]* { yylval.unique.idcontext = yytext; /* INCORRECT */
return IDENcode;
}
It should read
[[:alpha:]_][[:alnum:]_]* { yylval.unique.idcontext = strdup(yytext);
return IDENcode;
}
yytext points into the scanner's internal buffer, whose contents are modified every time the scanner is called. What you're seeing is a mild version of this problem, because your input is very short; if the input were long enough that yylex needed to refill the buffer from the input file, then you would see complete garbage in your idcontext fields. If you want to use the string later, you need to make a copy of it (and then you need to remember to free() the copy when you no longer need it, which can be a bit of a challenge.)
The other possible issue -- and honestly I don't know whether you consider it a problem or not, because you did not specify what output you expect from your debugging trace -- is that your right-recursive rule:
varlist: id comma varlist { createtnode($1.idcontext); }
| id { createtnode($1.idcontext); }
ends up calling createtnode on the ids in reverse order, because a bison reduction action is executed when the rule is matched. Using right-recursion like that means that the first varlist action to execute is actually the one corresponding to the last id.
If you want the actions to execute left to right, you need to use left-recursion:
varlist: varlist comma id { createtnode($3.idcontext); } /* See below */
| id { createtnode($1.idcontext); }
Left-recursion has other advantages. For example, it does not require all the ids (and commas) to pile up on the parser's internal stack waiting for the final reduction action.
Again, you don't show enough of your code to see how you use the result of these actions. It looks to me like you're trying to create a global linked list of variables, whose header you store in a global variable. (mynotes evidently points to the tail of the list, so it can't be used to recover the head.) If that's the case, then the change above should work fine. But it would be more normal to make the semantic value of varlist a list header, avoiding the use of global variables. That would result in code which looked more like this:
varlist: id comma varlist { $$ = append($1, createtnode($3.idcontext)); }
| id { $$ = append(newlist(), createtnode($1.idcontext); }

How to deal with function exits on a function that has several exit points?

I'm more of a student than I am a seasoned programmer and the other day I was refactoring a piece of code I wrote some time ago. In there, there was a function that was rather big in code size and had a structure like this:
if (eval)
return code;
...
if (different test)
return another code;
...
In all there were about 6 or 7 return points some of them with cleanup code inside of the branch. Some of them also responded to erroneous situations, paths where the function wouldn't fully process the input but rather return an error code.
Even though the code was commented and all it seemed to me hard on the eyes and difficult to read. So I was wondering if there are any best practices on the matter.
Reading code from all around the net I found different approaches to this matter. For example one would follow this scheme:
do {
whole body of the function;
while (false);
clean up code if necessary;
return code;
Mainly to be able to use break; sentences in different evaluations (since we were inside a loop) to exit the loop, do the cleanup if necessary and return the exit code. But that feels the same as gotos to me, with the limitation that they place to go to would only be forward in code.
Another one would be similar to mine, but have only one return statement at the end of the function and having a variable to hold error codes.
You can use goto for that.
code = firstCode;
if (condition != 0)
goto label;
code = secondCode;
if (anotherCondition != 0)
goto label;
label:
clean_up_code_if_necessary()
exit(code); // may be you should return from the function
but there could be many other options depending on the specific case.
Here is frequently used linux kernel idiom. When something fails, it rolls back and cleanup after previously executed code.
if(do_a()==FAIL)
goto fail_a;
if(do_b()==FAIL)
goto fail_c;
if(do_c()==FAIL)
goto fail_c;
/* rest of the code goes here */
/* if it's ok then set err to 0 and jump to ok */
err = 0;
goto ok;
// otherwise unroll what have been done
fail_c:
undo_c();
fail_b:
undo_b();
fail_a:
undo_a();
ok:
return err;
well , we need do differentiate between C and C++ , the way of handling things is quite different between C and C++.
In C , I would recommend use an Enum which states the current state of of the code , for example:
enum {State1,State2,Invalid_Argument,Error}
then , create a function that checkes whatever it needs, then return some constant from the enum above as return value:
int check_statement(arg1,arg2...)
and at last , use a switch case on the function above:
switch(check_statment(...)){
case state1:
...
return ...
case Error:
...
return..
}

How to prevent re-initializing pthread_rwlock_t

I'm declaring array of pthread_rwlock_t static global.
e.g. static pthread_rwlock_t cm[255];
Inside constructor I want to initialize one of the 255 mutex( I keep track with static counter)
Now I'm confused with
1) I don't want to re-initialize lock again, that is bad!
I thought reinitialize should return some error code, but it doesn't:
#include<stdio.h>
#include <pthread.h>
static pthread_rwlock_t cm[2];
int main()
{
int ret;
ret = pthread_rwlock_init(&cm[0], NULL);
ret = pthread_rwlock_wrlock(&cm[0]);
printf("Ret: %d\n", ret);
ret = pthread_rwlock_init(&cm[0], NULL);
printf("Ret: %d\n", ret);
ret = pthread_rwlock_wrlock(&cm[0]);
printf("Ret: %d\n", ret);
}
Result:
Ret: 0
Ret: 0
Ret: 0
Can anyone help, 1) If this is possible, then how? 2) If not what should be alternative approach?
EDIT 1:
I'm updating from comments/answers I got:
Instead, just put the rwlocks inside the objects they protect.
So I have n # of objects getting called, and will be using that many pthread_lock .. so disadvantage is memory. Hence I'm trying to improve on that part with global array of locks. Picking 256 to get good distribution.
It's undefined behavior to call pthread_rwlock_init (or analogously any of the pthread primitive init functions) more than once on the same object, and logically there's no way it would make sense to do so anyway since (as you've demonstrated) the object is already in use. You said in the comments on 2501's answer that you can't use pthread_once, but this makes no sense. If you're able to call pthread_rwlock_init, you can instead just call pthread_once using an init function which performs the call to pthread_rwlock_init.
However I really think you're experiencing an XY problem. There is no sense in maintaining a "global pool" of rwlocks and handing them out dynamically in constructors. Instead, just put the rwlocks inside the objects they protect. If you really want to hand them out from a global pool like you're doing, you need to keep track of which ones have been handed out independently of the job of initializing them, and have the task of initializing them after obtaining one, and destroying one before giving it back to the pool, be handled by the constructor/destructor for the object using them.
If you need static initialization, use PTHREAD_RWLOCK_INITIALIZER on your array.
static pthread_rwlock_t cm[2] = { PTHREAD_RWLOCK_INITIALIZER ,
PTHREAD_RWLOCK_INITIALIZER} ;
This is equivalent as calling pthread_rwlock_init() on every element with attr parameter specified as NULL, except that no error checking is performed.

How To Use SetConsoleCursorPosition Func

I just wrote the code for tower of hanoi in c and I wanted to show the solution in graphical mode using characters.
I want to use windows.h and SetConsoleCursorPosition function to move cursor in console.
Could you help me by telling me have does this function works and how to use it?Please give some examples.
Here's an example of how to call the SetConsoleCursorPosition function, taken from cplusplus:
void GoToXY(int column, int line)
{
// Create a COORD structure and fill in its members.
// This specifies the new position of the cursor that we will set.
COORD coord;
coord.X = column;
coord.Y = line;
// Obtain a handle to the console screen buffer.
// (You're just using the standard console, so you can use STD_OUTPUT_HANDLE
// in conjunction with the GetStdHandle() to retrieve the handle.)
// Note that because it is a standard handle, we don't need to close it.
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
// Finally, call the SetConsoleCursorPosition function.
if (!SetConsoleCursorPosition(hConsole, coord))
{
// Uh-oh! The function call failed, so you need to handle the error.
// You can call GetLastError() to get a more specific error code.
// ...
}
}
You can also find out how to use Win32 functions by checking the SDK documentation. Googling for the name of the function will usually turn up the appropriate doc page as the first hit.
For SetConsoleCursorPosition, the page is here, and for GetStdHandle, the page is here.

Building a lexer in C

I want to build a lexer in C and I am following the dragon book, I can understand the state transitions but how to implement them?
Is there a better book?
The fact that I have to parse a string through a number of states so that I can tell whether the string is acceptable or not!
You can implement simple state transitions with a single state variable, for example if you want to cycle through the states start->part1->part2->end then you can use an enum to keep track of the current state and use a switch statement for the code you want to run in each state.
enum state { start=1, part1, part2, end} mystate;
// ...
mystate = start;
do {
switch (mystate) {
case start:
// ...
case part1:
// ...
case part2:
// ...
if (part2_end_condition) mystate = end; // state++ will also work
// Note you could also set the state back to part1 on some condition here
// which creates a loop
break;
}
} while (mystate != end);
For more complex state transitions that depend on several variables, you should use tables/arrays like this:
var1 var2 var_end next_state
0 0 0 state1
0 1 0 state2
1 0 0 state3
1 1 0 state4
-1 -1 1 state_end // -1 represents "doesn't matter" here
G'day,
Assuming you mean The Dragon book on compiler design, I'd recommend having a look around this page on compiler tools.
The page itself is quite small but has links through to various excellent resources on lexical analysers.
HTH
cheers,
There's more than one way to do it. Every regular expression corresponds directly to a simple structured program. For example, an expression for numbers could be this:
// regular expression
digit* [.digit*]
and the corresponding C code would be:
// corresponding code
while(DIGIT(*pc)) pc++;
if (*pc=='.'){
pc++;
while(DIGIT(*pc)) pc++;
}
The transition-table way of building lexers is, in my opinion, needlessly complicated, and obviously runs slower.
If you're looking for a more modern treatment than the dragon book(s) : Andrew W. Appel and Maia Ginsburg, Modern Compiler Implementation in C, Cambridge University Press, 2008.
Chapter 2 is focused on Lexical Analysis : Lexical tokens, Regular expressions, Finite automata; Nondeterministic Finite Automata; Lexical analyzer generators
Look at the Table of Contents
The program flex (a clone of lex) will create a lexer for you.
Given an input file with the lexer rules, it will produce a C file with an implementation of a lexer for those rules.
You can thus check the output of flex for how to write a lexer in C. That is, if you don't just want to use flex's lexer...

Resources