0

I've the following MQL4/5 code:

class MQL4 {
public:
  static double Ask() {
    MqlTick _tick;
    SymbolInfoTick(_Symbol, _tick);
    return _tick.ask;
    // Overriding Ask variable to become a function call.
    #define Ask MQL4::Ask()
  }

};

void start() {
  double ask = Ask; // line 14
};

However it fails to compile under MQL4 or MQL5 as per errors:

> mql /s /mql5 Test.mqh
MQL4/MQL5 Compiler build 1162 (02 Jul 2015)
Test.mqh : information: Checking 'Test.mqh'
Test.mqh(14,16) : error 320: 'Ask' - too complex, simplify the macro
Test.mqh(14,16) : error 239: '::' - syntax error
Test.mqh(14,16) : error 239: '::' - syntax error
Test.mqh(14,16) : error 239: '::' - syntax error
Test.mqh(14,16) : error 239: '::' - syntax error
Test.mqh(14,16) : error 239: '::' - syntax error
Test.mqh(14,16) : error 239: '::' - syntax error
Test.mqh(14,16) : error 239: '::' - syntax error
Test.mqh(14,16) : error 149: unexpected token
Test.mqh(14,16) : error 149: ')' - unexpected token
Test.mqh(14,16) : error 157: 'MQL4' - expression expected
Test.mqh(14,10) : warning 31: variable 'ask' not used
 : information: Result 11 error(s), 1 warning(s)

Same errors with the latest 1498 build.

Basically it's saying that Ask macro is too complex macro. Although it works fine when I rename Ask() method to GetAsk() and update the macro definition,
however
I'd like to understand
if there is any other solution without having to renaming it.

Is there any syntax that I can define a macro substitution which can understand the following macro:

#define Ask MQL4::Ask()

without having to rename it while still keeping it in the static class method?

Stanislav Kralin
  • 11,070
  • 4
  • 35
  • 58
kenorb
  • 155,785
  • 88
  • 678
  • 743

2 Answers2

1

YES, but ..., no!
#define substitution works fine, but ...
but Ask is a reserved word, which confuses the compiler.

The problem is actually with the limited capabilites of the compiler pre-processor,
not with the .method()'s "same name".

The #define directive, both non-parametric and parametric, substitution capabilities were tested to the limits of the published MQL4/5 language syntax.


Case[6] finally proves,

the Class.<_method_>() can have the same name .Ask(), but it cannot be the same as the #define-s <_literal_symbol_to_substitute_>

//+------------------------------------------------------------------+
//|                                   StackOverflow__test_DEFINE.mq4 |
//|                                       Copyright © 1987-2017 [ME] |
//|                                                       nowhere.no |
//+------------------------------------------------------------------+
#property strict
 // -------------------------------------------------------------------------------------------------------------------------
/*                                                       // [Case[1] FAILS BELOW
#define               Ask MQL4::Ask( True )              // [Case[1] // Overriding Ask variable to become a function call. */

class MQL4 { 
     public:
     static double Ask( bool FakeSyntaxSUGAR = False ) { // [Case[1] FAILS HERE TO PROCESS EXPANDED PRE-PROCESSOR #define SUBSTITUTION]
                        MqlTick _tick;
                        SymbolInfoTick( _Symbol,
                                        _tick
                                        );
                        return _tick.ask;
         }
};

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+

void OnStart() {

 // -------------------------------------------------------------------------------------------------------------------------
/*                                                       // [Case[2] FAILS
#define               Ask MQL4::Ask( True )              // [Case[2] // Overriding Ask variable to become a function call. */
  // double ask     = Ask;                               // [Case[2] FAILS TO COMPILE, ERROR on "Ask;"]


  // ------------------------------------------------------------------------------------------------------------------------
  // double askMQL4 = MQL4::Ask( True );                 // [Case[3] OK    TO COMPILE EXPLICIT CALL TO an explicit absolute reference to a method-name]


 // -------------------------------------------------------------------------------------------------------------------------
/*                                                       // [Case[4] OK */
     MQL4* aPtrToINSTANCE = new MQL4();                  // [Case[4]
  // double askINST = aPtrToINSTANCE.Ask( False );       // [Case[4] OK    TO COMPILE EXPLICIT CALL TO aPtrToINSTANCE-referred instance of Class ]

 // -------------------------------------------------------------------------------------------------------------------------
/*                                                       // [Case[5] FAILS
#define               Ask aPtrToINSTANCE.Ask( False )    // [Case[5] */
  // double askINST = Ask;                               // [Case[5] FAILS TO PRE-PROCESS #define HERE ]


 // -------------------------------------------------------------------------------------------------------------------------
/*                                                       // [Case[6] OK */
#define               Ask_with_SomeOtherDEFINE_NAME aPtrToINSTANCE.Ask( False )
     double askINST = Ask_with_SomeOtherDEFINE_NAME;     // [Case[6] OK    TO CALL THE .Ask() METHOD AS THE PRE-PROCESSOR <_SYMBOL_TO_SUBSTITE_> WAS #define-d AS NON-COLLIDING]

//    **   *   ****        ****        *****        *****
//    ***  *  **   *      **   *       **           **   *
//    ** * *  **   *      **   *       ***          **    *
//    **  **  **   *      ** * *       **           **   * 
//    **   *   ****  **    ****   **   *****  **    *****  **
//                   *         *  
}; 
// ------------------------------------------------------------------

Epilogue:

As I have posted somewhere in some other MQL4-posts, after having some extensive testing of the capabilities available from the #define directive based pre-compiler substitutions ( for version management purposes et al ), I could but draw a conclusion to try to avoid using this feature, as the resulting problems were far more expensive ( surprising string-handling limitations, uncertainties about the continuing language creeps, unpredictable results of syntax-sugar tricks after next Build releases etc. ) than beneficial for the purposes intended.

Community
  • 1
  • 1
user3666197
  • 1
  • 6
  • 50
  • 92
  • So in other words you're saying it's not possible without renaming the variable or method? – kenorb Jan 17 '17 at 16:09
  • 'Ask is a reserved word, which confuses the compiler' this is not correct, if you change `Ask` to `Foo` across the code, the compiler will show the same errors about too _complex macro_, so it's not about a reserved word. – kenorb Jan 17 '17 at 16:11
  • In which **`Case[id#]`**? Well, no one can rename the hard-coded "system register" **`Ask`**. Next, the weakest point is the `#define` pre-compiler substitution, that sequentially substitutes all appearences of **each** `<_literal_symbol_to_substitute_>` after which the lexer typically gets panic. **Sorry, this is outside of the control of the MQL4/5-side code-design.** – user3666197 Jan 17 '17 at 16:17
  • Your first sentence saying that ('Ask is a reserved word, which confuses the compiler'). The `Ask` variable in MQL5 doesn't exist and the same happens there, so it's not about reserved word. I think the main problem is that value of macro definition has macro name in it, so every `Ask` is replaced with value of it, then the same happens after replacement over and over again until few iterations when compiler realizes that it's too complex. – kenorb Jan 17 '17 at 16:18
  • Yes, this was mentioned in the previous comment. – user3666197 Jan 17 '17 at 16:20
  • 1
    If you uncomment and re-test the different `[Case[id#]]`-s, the error messages will vary a bit, be different as per where the collision started, but typically show a divergent panic of the pre-compiler substitution combined with lexer panic on growing complexity of the intermediate representation it cannot somehow satisfactorily terminate in code-structure analysis and gaves up in a panic state after some 30 nesting levels. – user3666197 Jan 17 '17 at 16:23
0

macro substitution should be declared somewhere away from the function. try to move #define Ask MQL4::Ask() above the class declaration or to the first line of your program

UPD. after conversation it turned out that macro should have different name.

#define method (Class::method()) //doesnt work, 
#define method (Class::Method()) //or (Class::method_()) is fine
Daniel Kniaz
  • 4,603
  • 2
  • 14
  • 20
  • It won't make any difference, as compiler won't see it as in the function. It's just placed after Ask method definition for convenience. – kenorb Jan 17 '17 at 14:40
  • you are doing sth wrong. look: your code [link](https://gyazo.com/1060fee05e55ea39f6df134750487587) and output [link](https://gyazo.com/325f032e3b7fecbcc3465550138d95f2) - moving macro away and putting all in () is enough – Daniel Kniaz Jan 17 '17 at 14:47
  • The order doesn't matter, but in your code you've already renamed `Ask` to `ASK`, then it works fine. But I want point `Ask` macro into `MQL4::Ask()` explicitly. Using `ASK` with capital letters isn't the standard [predefined variable](https://docs.mql4.com/predefined/ask) in MQL4, since existing MQL4 code running under MQL5 would be using that class would use `Ask`, not `ASK`. So workaround changing the names is the one which I'd like to avoid. – kenorb Jan 17 '17 at 14:52
  • indeed. if renaming function to ask() - it works. maybe it doesnt want to have macro and function name equal – Daniel Kniaz Jan 17 '17 at 14:55