Compare commits

..

30 Commits

Author SHA1 Message Date
Viacheslav Demydiuk 8317ce9604 MtApi5: fixed issue in iCustom - incorrect name of parameters 2026-07-08 16:59:02 +03:00
Viacheslav Demydiuk 3699b73cf7 Issue #290: provide information about Period (Timeframe) in event Mt5TimeBar 2026-04-06 21:55:59 +03:00
Viacheslav Demydiuk 9d178280d0 Issue #290: MQL5 - added Timeframe into event MtTimeBarEvent 2026-04-06 21:53:50 +03:00
Viacheslav Demydiuk a8bb1a3af9 Issue #261: MQL5 - reset flag _is_ticks_locked in function Execute_UnlockTicks 2026-04-06 21:23:48 +03:00
Viacheslav Demydiuk fa1e6b6c62 Issue #296: MtApi5 - Added property CommandTimeout to define time for waiting result of response from MetaTrader. Default value 30 sec 2026-04-06 20:22:10 +03:00
Viacheslav Demydiuk 249b0f9fbb Issue #262: function GetQuotes load data from MT instead of using cached quotes 2025-12-05 23:43:27 +02:00
Viacheslav Demydiuk 0c874773e5 Issue #241: fixed issue of incorrect value of CloseTime in orders received from TradeMonitor 2025-10-08 16:23:16 +03:00
Viacheslav Demydiuk 2c4d9b130b MQL4: update function OrderClose to avoid compile warnings 2025-10-08 10:59:05 +03:00
Viacheslav Demydiuk a5b8e33611 Issue #246: fixed type of parameter 'Deviation' in functions iBands, iBandsOnArray (MT4) 2025-10-07 17:03:02 +03:00
Viacheslav Demydiuk 2f0ccae238 MQL5: fixed warnings of compiling json.mqh 2025-10-06 23:26:48 +03:00
Viacheslav Demydiuk 565735c3c5 MtService: fixed crash on disconnect last expert in MT terminal 2025-10-06 12:07:41 +03:00
Viacheslav Demydiuk 7b5f740a77 MtApi5: added fleld 'Flags' into MqlTick 2025-10-05 20:58:24 +03:00
Viacheslav Demydiuk c536585cd2 Issue #284: MtApi5/MQL5 - added function GetSymbols 2025-09-30 16:14:13 +03:00
Viacheslav Demydiuk 92322e866e Issue #284: MtApi4/MQL4 - added function GetSymbols 2025-09-27 17:29:00 +03:00
Viacheslav Demydiuk 96674d8763 MQL5: fixed parsing arguments of function iCustom 2025-09-23 11:31:43 +03:00
Viacheslav Demydiuk 5808756113 MQL4: fixed parsing arguments of function iCustom 2025-09-23 11:26:58 +03:00
Viacheslav Demydiuk 972df57028 Merge branch 'master' into dev 2025-07-28 23:20:33 +03:00
Viacheslav Demydiuk 6c1cb92f1b MtApi5: fixed typo in function iStochastic 2025-07-28 23:12:21 +03:00
Viacheslav Demydiuk ff871e5e06 MtApi5: implement function iFractals instead of mistake function iForce 2025-07-28 22:57:46 +03:00
Viacheslav Demydiuk c7b8956c99 MtApi5: fixed typo in function iChaikin 2025-07-28 22:51:35 +03:00
Viacheslav Demydiuk db3db18391 MQL5: fixed typo in function iSAR 2025-07-28 22:37:15 +03:00
Viacheslav Demydiuk 143cc33c60 MtApi5: fix type in function iStochastic 2025-07-28 22:34:28 +03:00
Viacheslav Demydiuk 541fc2364b MQL5: don't use EMPTY_VALUE as initial value for times 2025-07-25 17:52:06 +03:00
Viacheslav Demydiuk 78b4b7039b MQL5: changed MQL5_DLLS_ALLOWED to MQL_DLLS_ALLOWED 2025-07-25 17:49:30 +03:00
Viacheslav Demydiuk 4a61ab079c MQL5: fixed parameter in function iChaikin 2025-07-25 17:43:07 +03:00
Viacheslav Demydiuk 69d98b66b3 MtApi5: updated paramter's names in function iCustom 2025-07-25 17:11:55 +03:00
Viacheslav Demydiuk 6b3d54b9d5 MtApi5: added default value to properites of MqlParam for correct json serialization 2025-01-09 17:06:36 +02:00
Viacheslav Demydiuk ba1754d59b MtApi/MtApi5: updated logic of connection with requesting expert list and quotes 2024-12-21 23:12:59 +02:00
Viacheslav Demydiuk b89f00d310 Added missed boost headers files 2024-11-14 14:16:28 +02:00
Viacheslav Demydiuk 19d9cb23d3 MtService: include string to fix build 2024-11-14 12:35:46 +02:00
42 changed files with 4113 additions and 2055 deletions
+1 -1
View File
@@ -89,7 +89,7 @@ namespace MtApi.Monitors
{
//get closed orders from history with actual values
var historyOrders = ApiClient.GetOrders(OrderSelectSource.MODE_HISTORY) ?? [];
closedOrders = closeOrdersTemp.Where(cot => historyOrders.Find(a => a.Ticket == cot.Ticket) != null).ToList();
closedOrders = historyOrders.Where(cot => closeOrdersTemp.Find(a => a.Ticket == cot.Ticket) != null).ToList();
}
}
+52 -52
View File
@@ -27,7 +27,6 @@ namespace MtApi
private readonly Dictionary<MtEventTypes, Action<int, string>> _mtEventHandlers = [];
private HashSet<int> _experts = [];
private Dictionary<int, MtQuote> _quotes = [];
private readonly EventWaitHandle _quotesWaiter = new AutoResetEvent(false);
private MtConnectionState _connectionState = MtConnectionState.Disconnected;
private int _executorHandle;
@@ -83,7 +82,6 @@ namespace MtApi
///</summary>
public List<MtQuote> GetQuotes()
{
_quotesWaiter.WaitOne(10000); // wait 10 sec for loading all quotes from MetaTrader
lock (_locker)
{
return _quotes.Values.ToList();
@@ -504,6 +502,12 @@ namespace MtApi
Dictionary<string, object> cmdParams = new() { { "Pool", (int)pool} };
return SendCommand<List<MtOrder>>(ExecutorHandle, MtCommandType.GetOrders, cmdParams);
}
public List<string>? GetSymbols(bool selected)
{
Dictionary<string, object> cmdParams = new() { { "Selected", selected } };
return SendCommand<List<string>>(ExecutorHandle, MtCommandType.GetSymbols, cmdParams);
}
#endregion
#region Checkup
@@ -1133,7 +1137,7 @@ namespace MtApi
return SendCommand<double>(ExecutorHandle, MtCommandType.iBearsPower, cmdParams);
}
public double iBands(string symbol, int timeframe, int period, int deviation, int bandsShift, int appliedPrice, int mode, int shift)
public double iBands(string symbol, int timeframe, int period, double deviation, int bandsShift, int appliedPrice, int mode, int shift)
{
Dictionary<string, object> cmdParams = new() { { "Symbol", symbol },
{ "Timeframe", timeframe }, { "Period", period },
@@ -1143,7 +1147,7 @@ namespace MtApi
return SendCommand<double>(ExecutorHandle, MtCommandType.iBands, cmdParams);
}
public double iBandsOnArray(double[] array, int total, int period, int deviation, int bandsShift, int mode, int shift)
public double iBandsOnArray(double[] array, int total, int period, double deviation, int bandsShift, int mode, int shift)
{
Dictionary<string, object> cmdParams = new() { { "Total", total },
{ "Period", period }, { "Deviation", deviation },
@@ -3041,7 +3045,6 @@ namespace MtApi
ConnectionStateChanged?.Invoke(this, new MtConnectionEventArgs(MtConnectionState.Connecting, message));
var client = new MtRpcClient(host, port, new RpcClientLogger(Log));
client.ExpertList += Client_ExpertList;
client.ExpertAdded += Client_ExpertAdded;
client.ExpertRemoved += Client_ExpertRemoved;
client.MtEventReceived += Client_MtEventReceived;
@@ -3052,13 +3055,44 @@ namespace MtApi
{
await client.Connect();
Log.Info($"Connected to {host}:{port}");
var experts = client.RequestExpertsList();
if (experts == null || experts.Count == 0)
{
var errorMessage = "Failed to load expert list";
Log.Error(errorMessage);
client.Disconnect();
ConnectionStateChanged?.Invoke(this, new MtConnectionEventArgs(MtConnectionState.Failed, errorMessage));
throw new Exception($"Connection to {host}:{port} failed. Error: {errorMessage}");
}
// Load quotes
Dictionary<int, MtQuote> quotes = [];
foreach (var handle in experts)
{
var quote = GetQuote(client, handle);
if (quote != null)
quotes[handle] = quote;
}
lock (_locker)
{
_client = client;
_experts = experts;
_quotes = quotes;
if (_executorHandle == 0)
_executorHandle = (_experts.Count > 0) ? _experts.ElementAt(0) : 0;
_connectionState = MtConnectionState.Connected;
}
client.NotifyClientReady();
if (IsTesting())
{
BacktestingReady();
}
ConnectionStateChanged?.Invoke(this, new MtConnectionEventArgs(MtConnectionState.Connected, $"Connected to {host}:{port}"));
QuoteList?.Invoke(this, new(quotes.Values.ToList()));
}
catch (Exception e)
{
@@ -3102,7 +3136,11 @@ namespace MtApi
private T? SendCommand<T>(int expertHandle, MtCommandType commandType, object? payload = null)
{
var client = Client;
return SendCommand<T>(Client, expertHandle, commandType, payload);
}
private T? SendCommand<T>(MtRpcClient? client, int expertHandle, MtCommandType commandType, object? payload = null)
{
if (client == null)
{
Log.Warn("SendCommand: No connection");
@@ -3143,11 +3181,6 @@ namespace MtApi
Task.Run(() => _mtEventHandlers[(MtEventTypes)e.EventType](e.ExpertHandle, e.Payload));
}
private void Client_ExpertList(object? sender, MtExpertListEventArgs e)
{
Task.Run(() => ProcessExpertList(e.Experts));
}
private void Client_ExpertAdded(object? sender, MtExpertEventArgs e)
{
Task.Run(() => ProcessExpertAdded(e.Expert));
@@ -3213,39 +3246,6 @@ namespace MtApi
OnLockTicks?.Invoke(this, new MtLockTicksEventArgs(expertHandle, e.Instrument));
}
private void ProcessExpertList(HashSet<int> experts)
{
if (experts == null || experts.Count == 0)
{
Log.Warn("ProcessExpertList: expert list invalid or empty");
return;
}
Dictionary<int, MtQuote> quotes = [];
foreach (var handle in experts)
{
var quote = GetQuote(handle);
if (quote != null)
quotes[handle] = quote;
}
lock (_locker)
{
_experts = experts;
_quotes = quotes;
if (_executorHandle == 0)
_executorHandle = (_experts.Count > 0) ? _experts.ElementAt(0) : 0;
}
_quotesWaiter.Set();
QuoteList?.Invoke(this, new(quotes.Values.ToList()));
if (IsTesting())
{
BacktestingReady();
}
}
private void ProcessExpertAdded(int handle)
{
Log.Debug($"ProcessExpertAdded: {handle}");
@@ -3260,7 +3260,7 @@ namespace MtApi
if (added)
{
var quote = GetQuote(handle);
var quote = GetQuote(Client, handle);
if (quote != null)
{
lock (_locker)
@@ -3295,19 +3295,19 @@ namespace MtApi
QuoteRemoved?.Invoke(this, new MtQuoteEventArgs(quote));
}
private MtQuote? GetQuote(int expertHandle)
private MtQuote? GetQuote(MtRpcClient? client, int expertHandle)
{
Log.Debug($"GetQuote: expertHandle = {expertHandle}");
var e = SendCommand<MtRpcQuote>(expertHandle, MtCommandType.GetQuote);
if (e == null || string.IsNullOrEmpty(e.Instrument) || e.Tick == null)
var q = SendCommand<MtRpcQuote>(client, expertHandle, MtCommandType.GetQuote);
if (q == null || string.IsNullOrEmpty(q.Instrument) || q.Tick == null)
return null;
MtQuote quote = new()
{
Instrument = e.Instrument,
Bid = e.Tick.Bid,
Ask = e.Tick.Ask,
Instrument = q.Instrument,
Bid = q.Tick.Bid,
Ask = q.Tick.Ask,
ExpertHandle = expertHandle,
};
+2 -1
View File
@@ -287,6 +287,7 @@
SymbolInfoTick = 288,
SymbolInfoDouble = 289,
GetQuote = 290
GetQuote = 290,
GetSymbols = 291
}
}
+3 -3
View File
@@ -3,8 +3,8 @@
public class MqlParam
{
public ENUM_DATATYPE DataType { get; set; }
public long? IntegerValue { get; set; }
public double? DoubleValue { get; set; }
public string? StringValue { get; set; }
public long IntegerValue { get; set; } = 0;
public double DoubleValue { get; set; } = 0.0;
public string StringValue { get; set; } = String.Empty;
}
}
+8
View File
@@ -5,12 +5,18 @@ namespace MtApi5
public class MqlTick
{
public MqlTick(DateTime time, double bid, double ask, double last, ulong volume)
: this(time, bid, ask, last, volume, 0)
{
}
public MqlTick(DateTime time, double bid, double ask, double last, ulong volume, ENUM_TICK_FLAGS flags)
{
MtTime = Mt5TimeConverter.ConvertToMtTime(time);
this.bid = bid;
this.ask = ask;
this.last = last;
this.volume = volume;
this.flags = flags;
}
public MqlTick()
@@ -27,6 +33,7 @@ namespace MtApi5
last = tick.Last;
volume = tick.Volume;
volume_real = tick.VolumeReal;
flags = (ENUM_TICK_FLAGS)tick.Flags;
}
}
@@ -37,6 +44,7 @@ namespace MtApi5
public double last { get; set; } // Price of the last deal (Last)
public ulong volume { get; set; } // Volume for the current Last price
public double volume_real { get; set; } // Volume for the current Last price with greater accuracy
public ENUM_TICK_FLAGS flags { get; set; } // Tick flags (used for analyzing to find out what data have been changed)
public DateTime time => Mt5TimeConverter.ConvertFromMtTime(MtTime);
}
+12
View File
@@ -862,6 +862,18 @@ namespace MtApi5
STO_CLOSECLOSE = 1 //Calculation is based on Close/Close prices
}
[Flags]
public enum ENUM_TICK_FLAGS
{
TICK_FLAG_NONE = 0,
TICK_FLAG_BID = 2, // Tick has changed a Bid price
TICK_FLAG_ASK = 4, // Tick has changed an Ask price
TICK_FLAG_LAST = 8, // Tick has changed the last deal price
TICK_FLAG_VOLUME = 16, // Tick has changed a volume
TICK_FLAG_BUY = 32, // Tick is a result of a buy deal
TICK_FLAG_SELL = 64 // Tick is a result of a sell deal
}
#endregion //Price Constants
#region Smoothing Methods
+3 -1
View File
@@ -4,15 +4,17 @@ namespace MtApi5
{
public class Mt5TimeBarArgs: EventArgs
{
internal Mt5TimeBarArgs(int expertHandle, string symbol, MqlRates rates)
internal Mt5TimeBarArgs(int expertHandle, string symbol, ENUM_TIMEFRAMES timeframe, MqlRates rates)
{
ExpertHandle = expertHandle;
Rates = rates;
Symbol = symbol;
Timeframe = timeframe;
}
public int ExpertHandle { get; }
public string Symbol { get; }
public ENUM_TIMEFRAMES Timeframe { get; }
public MqlRates Rates { get; }
}
}
+105 -86
View File
@@ -2,6 +2,7 @@
using MtClient;
using MtApi5.MtProtocol;
using MtApi5.MtProtocol.ICustomRequest;
using System.Data;
namespace MtApi5
{
@@ -31,12 +32,24 @@ namespace MtApi5
private HashSet<int> _experts = [];
private Dictionary<int, Mt5Quote> _quotes = [];
private readonly EventWaitHandle _quotesWaiter = new AutoResetEvent(false);
private volatile int _command_timeout = 30000; // 30 seconds
#endregion
#region Public Methods
private IMtLogger Log { get; }
// Time in milliseconds to wait for a response from MetaTrader for a command. Default is 30 seconds.
public int CommandTimeout
{
get => _command_timeout;
set
{
if (value <= 0)
throw new ArgumentException("Command timeout must be greater than zero.");
_command_timeout = value;
}
}
public MtApi5Client(IMtLogger? log = null)
{
_mtEventHandlers[Mt5EventTypes.OnBookEvent] = ReceivedOnBookEvent;
@@ -94,17 +107,13 @@ namespace MtApi5
{
if (_connectionState == Mt5ConnectionState.Connected
|| _connectionState == Mt5ConnectionState.Connecting)
{
return;
}
_connectionState = Mt5ConnectionState.Connecting;
}
ConnectionStateChanged?.Invoke(this, new Mt5ConnectionEventArgs(Mt5ConnectionState.Connecting, $"Connecting to {host}:{port}"));
var client = new MtRpcClient(host, port, new RpcClientLogger(Log));
client.ExpertList += Client_ExpertList;
client.ExpertAdded += Client_ExpertAdded;
client.ExpertRemoved += Client_ExpertRemoved;
client.MtEventReceived += Client_MtEventReceived;
@@ -115,13 +124,35 @@ namespace MtApi5
{
await client.Connect();
Log.Info($"Connected to {host}:{port}");
var experts = client.RequestExpertsList();
if (experts == null || experts.Count == 0)
{
var errorMessage = "Failed to load expert list";
Log.Error(errorMessage);
client.Disconnect();
ConnectionStateChanged?.Invoke(this, new Mt5ConnectionEventArgs(Mt5ConnectionState.Failed, errorMessage));
throw new Exception($"Connection to {host}:{port} failed. Error: {errorMessage}");
}
var quotes = LoadQuotes(client, experts);
lock (_locker)
{
_client = client;
_experts = experts;
_quotes = quotes;
if (_executorHandle == 0)
_executorHandle = (_experts.Count > 0) ? _experts.ElementAt(0) : 0;
_connectionState = Mt5ConnectionState.Connected;
}
client.NotifyClientReady();
if (IsTesting())
BacktestingReady();
ConnectionStateChanged?.Invoke(this, new Mt5ConnectionEventArgs(Mt5ConnectionState.Connected, $"Connected to {host}:{port}"));
QuoteList?.Invoke(this, new(quotes.Values.ToList()));
}
catch (Exception e)
{
@@ -135,6 +166,18 @@ namespace MtApi5
}
}
private Dictionary<int, Mt5Quote> LoadQuotes(MtRpcClient client, HashSet<int> experts)
{
Dictionary<int, Mt5Quote> quotes = [];
foreach (var handle in experts)
{
var quote = GetQuote(client, handle);
if (quote != null)
quotes[handle] = quote;
}
return quotes;
}
///<summary>
///Disconnect from MetaTrader API. Async method.
///</summary>
@@ -154,18 +197,35 @@ namespace MtApi5
}
///<summary>
///Load quotes connected into MetaTrader API (deprecated)
///Load quotes connected into MetaTrader API
///</summary>
public IEnumerable<Mt5Quote> GetQuotes()
{
// this function is deprecated.
// should be used event OnQuoteList
_quotesWaiter.WaitOne(10000); // wait 10 sec for loading all quotes from MetaTrader
MtRpcClient? client;
HashSet<int> experts;
lock (_locker)
{
return _quotes.Values.ToList();
client = _client;
experts = new HashSet<int>(_experts);
}
if (client == null)
{
Log.Warn("GetQuotes: No connection");
throw new Exception("No connection");
}
var quotes = LoadQuotes(client, experts);
return quotes.Values.ToList();
}
///<summary>
///Load symbols
///</summary>
public List<string>? GetSymbols(bool selected)
{
Dictionary<string, object> cmdParams = new() { { "Selected", selected } };
return SendCommand<List<string>>(ExecutorHandle, Mt5CommandType.GetSymbols, cmdParams);
}
///<summary>
@@ -2644,7 +2704,7 @@ namespace MtApi5
{
Dictionary<string, object> cmdParams = new() { { "Symbol", symbol ?? string.Empty }, { "Period", (int)period },
{ "FastMaPeriod", fastMaPeriod }, { "SlowMaPeriod", slowMaPeriod},
{ "MaMethod", (int)maMethod }, { "appliedVolume", (int)appliedVolume } };
{ "MaMethod", (int)maMethod }, { "AppliedVolume", (int)appliedVolume } };
return SendCommand<int>(ExecutorHandle, Mt5CommandType.iChaikin, cmdParams);
}
@@ -2710,14 +2770,14 @@ namespace MtApi5
}
///<summary>
///The function returns the handle of the Force Index indicator.
///The function returns the handle of the Fractals indicator.
///</summary>
///<param name="symbol">The symbol name of the security, the data of which should be used to calculate the indicator.</param>
///<param name="period">The value of the period can be one of the ENUM_TIMEFRAMES enumeration values, 0 means the current timeframe.</param>
public int iForce(string symbol, ENUM_TIMEFRAMES period)
public int iFractals(string symbol, ENUM_TIMEFRAMES period)
{
Dictionary<string, object> cmdParams = new() { { "Symbol", symbol ?? string.Empty }, { "Period", (int)period } };
return SendCommand<int>(ExecutorHandle, Mt5CommandType.iForce, cmdParams);
return SendCommand<int>(ExecutorHandle, Mt5CommandType.iFractals, cmdParams);
}
///<summary>
@@ -2949,7 +3009,7 @@ namespace MtApi5
{
Dictionary<string, object> cmdParams = new() { { "Symbol", symbol ?? string.Empty }, { "Period", (int)period },
{ "Kperiod", Kperiod }, { "Dperiod", Dperiod }, { "Slowing", slowing },
{ "MaMethod", (int)maMethod }, { "priceField", (int)priceField } };
{ "MaMethod", (int)maMethod }, { "PriceField", (int)priceField } };
return SendCommand<int>(ExecutorHandle, Mt5CommandType.iStochastic, cmdParams);
}
@@ -3035,8 +3095,8 @@ namespace MtApi5
public int iCustom(string symbol, ENUM_TIMEFRAMES period, string name, double[] parameters)
{
Dictionary<string, object> cmdParams = new() { { "Symbol", symbol ?? string.Empty },
{ "Period", (int)period }, { "Name", name ?? string.Empty},
{ "Parameters", parameters }, { "ParamsType", ParametersType.Double} };
{ "Timeframe", (int)period }, { "Name", name ?? string.Empty},
{ "Params", parameters }, { "ParamsType", ParametersType.Double} };
return SendCommand<int>(ExecutorHandle, Mt5CommandType.iCustom, cmdParams);
}
@@ -3050,7 +3110,7 @@ namespace MtApi5
public int iCustom(string symbol, ENUM_TIMEFRAMES period, string name, int[] parameters)
{
Dictionary<string, object> cmdParams = new() { { "Symbol", symbol ?? string.Empty },
{ "Period", (int)period }, { "Name", name ?? string.Empty }, { "Parameters", parameters },
{ "Timeframe", (int)period }, { "Name", name ?? string.Empty }, { "Params", parameters },
{ "ParamsType", ParametersType.Int } };
return SendCommand<int>(ExecutorHandle, Mt5CommandType.iCustom, cmdParams);
}
@@ -3065,8 +3125,8 @@ namespace MtApi5
public int iCustom(string symbol, ENUM_TIMEFRAMES period, string name, string[] parameters)
{
Dictionary<string, object> cmdParams = new() { { "Symbol", symbol ?? string.Empty },
{ "Period", (int)period }, { "Name", name ?? string.Empty },
{ "Parameters", parameters }, { "ParamsType", ParametersType.String } };
{ "Timeframe", (int)period }, { "Name", name ?? string.Empty },
{ "Params", parameters }, { "ParamsType", ParametersType.String } };
return SendCommand<int>(ExecutorHandle, Mt5CommandType.iCustom, cmdParams);
}
@@ -3080,8 +3140,8 @@ namespace MtApi5
public int iCustom(string symbol, ENUM_TIMEFRAMES period, string name, bool[] parameters)
{
Dictionary<string, object> cmdParams = new() { { "Symbol", symbol ?? string.Empty },
{ "Period", (int)period }, { "Name", name ?? string.Empty },
{ "Parameters", parameters }, { "ParamsType", ParametersType.Boolean } };
{ "Timeframe", (int)period }, { "Name", name ?? string.Empty },
{ "Params", parameters }, { "ParamsType", ParametersType.Boolean } };
return SendCommand<int>(ExecutorHandle, Mt5CommandType.iCustom, cmdParams);
}
@@ -3345,11 +3405,6 @@ namespace MtApi5
Task.Run(() => _mtEventHandlers[(Mt5EventTypes)e.EventType](e.ExpertHandle, e.Payload));
}
private void Client_ExpertList(object? sender, MtExpertListEventArgs e)
{
Task.Run(()=>ProcessExpertList(e.Experts));
}
private void Client_ExpertAdded(object? sender, MtExpertEventArgs e)
{
Task.Run(() => ProcessExpertAdded(e.Expert));
@@ -3360,39 +3415,6 @@ namespace MtApi5
Task.Run(() => ProcessExpertRemoved(e.Expert));
}
private void ProcessExpertList(HashSet<int> experts)
{
if (experts == null || experts.Count == 0)
{
Log.Warn("ProcessExpertList: expert list invalid or empty");
return;
}
Dictionary<int, Mt5Quote> quotes = [];
foreach (var handle in experts)
{
var quote = GetQuote(handle);
if (quote != null)
quotes[handle] = quote;
}
lock (_locker)
{
_experts = experts;
_quotes = quotes;
if (_executorHandle == 0)
_executorHandle = (_experts.Count > 0) ? _experts.ElementAt(0) : 0;
}
_quotesWaiter.Set();
QuoteList?.Invoke(this, new(quotes.Values.ToList()));
if (IsTesting())
{
BacktestingReady();
}
}
private void ProcessExpertAdded(int handle)
{
Log.Debug($"ProcessExpertAdded: {handle}");
@@ -3407,14 +3429,9 @@ namespace MtApi5
if (added)
{
var quote = GetQuote(handle);
var quote = GetQuote(Client, handle);
if (quote != null)
{
lock (_locker)
{
_quotes[handle] = quote;
}
QuoteAdded?.Invoke(this, new Mt5QuoteEventArgs(quote));
}
else
@@ -3429,38 +3446,37 @@ namespace MtApi5
{
Log.Debug($"ProcessExpertRemoved: {handle}");
Mt5Quote? quote = null;
Mt5Quote? quote;
lock (_locker)
{
_quotes.TryGetValue(handle, out quote);
_quotes.Remove(handle);
_experts.Remove(handle);
if (_quotes.TryGetValue(handle, out quote))
_quotes.Remove(handle);
if (_executorHandle == handle)
_executorHandle = (_experts.Count > 0) ? _experts.ElementAt(0) : 0;
}
if (quote != null)
QuoteRemoved?.Invoke(this, new Mt5QuoteEventArgs(quote));
QuoteRemoved?.Invoke(this, new Mt5QuoteEventArgs(new Mt5Quote { Instrument = quote.Instrument, ExpertHandle = quote.ExpertHandle }));
}
private Mt5Quote? GetQuote(int expertHandle)
private Mt5Quote? GetQuote(MtRpcClient? client, int expertHandle)
{
Log.Debug($"GetQuote: expertHandle = {expertHandle}");
var e = SendCommand<MtQuote>(expertHandle, Mt5CommandType.GetQuote);
if (e == null || string.IsNullOrEmpty(e.Instrument) || e.Tick == null)
var q = SendCommand<MtQuote>(client, expertHandle, Mt5CommandType.GetQuote);
if (q == null || string.IsNullOrEmpty(q.Instrument) || q.Tick == null)
return null;
Mt5Quote quote = new()
{
Instrument = e.Instrument,
Bid = e.Tick.Bid,
Ask = e.Tick.Ask,
Instrument = q.Instrument,
Bid = q.Tick.Bid,
Ask = q.Tick.Ask,
ExpertHandle = expertHandle,
Volume = e.Tick.Volume,
Time = Mt5TimeConverter.ConvertFromMtTime(e.Tick.Time),
Last = e.Tick.Last
Volume = q.Tick.Volume,
Time = Mt5TimeConverter.ConvertFromMtTime(q.Tick.Time),
Last = q.Tick.Last
};
return quote;
@@ -3530,7 +3546,7 @@ namespace MtApi5
var e = JsonConvert.DeserializeObject<OnLastTimeBarEvent>(payload);
if (e == null || string.IsNullOrEmpty(e.Instrument) || e.Rates == null)
return;
OnLastTimeBar?.Invoke(this, new Mt5TimeBarArgs(expertHandle, e.Instrument, e.Rates));
OnLastTimeBar?.Invoke(this, new Mt5TimeBarArgs(expertHandle, e.Instrument, e.Timeframe, e.Rates));
}
private void ReceivedOnLockTicksEvent(int expertHandle, string payload)
@@ -3558,7 +3574,6 @@ namespace MtApi5
client = _client;
_client = null;
_quotes.Clear();
_experts.Clear();
_executorHandle = 0;
}
@@ -3572,7 +3587,11 @@ namespace MtApi5
private T? SendCommand<T>(int expertHandle, Mt5CommandType commandType, object? payload = null)
{
var client = Client;
return SendCommand<T>(Client, expertHandle, commandType, payload);
}
private T? SendCommand<T>(MtRpcClient? client, int expertHandle, Mt5CommandType commandType, object? payload = null)
{
if (client == null)
{
Log.Warn("SendCommand: No connection");
@@ -3582,7 +3601,7 @@ namespace MtApi5
var payloadJson = payload == null ? string.Empty : JsonConvert.SerializeObject(payload);
Log.Debug($"SendCommand: sending '{payloadJson}' ...");
var responseJson = client.SendCommand(expertHandle, (int)commandType, payloadJson);
var responseJson = client.SendCommand(expertHandle, (int)commandType, payloadJson, CommandTimeout);
Log.Debug($"SendCommand: received response JSON [{responseJson}]");
+1
View File
@@ -8,5 +8,6 @@
public double Last { get; set; } // Price of the last deal (Last)
public ulong Volume { get; set; } // Volume for the current Last price
public double VolumeReal { get; set; } // Volume for the current Last price with greater accuracy
public uint Flags { get; set; } // Tick flags
}
}
+2 -1
View File
@@ -259,6 +259,7 @@ namespace MtApi5.MtProtocol
OrderSendAsync = 302,
OrderCheck = 303,
Buy = 304,
Sell = 305
Sell = 305,
GetSymbols = 306
}
}
+1
View File
@@ -4,6 +4,7 @@
{
public MqlRates? Rates { get; set; }
public string? Instrument { get; set; }
public ENUM_TIMEFRAMES Timeframe { get; set; }
public int ExpertHandle { get; set; }
}
}
+7 -7
View File
@@ -8,12 +8,12 @@
ExpertList = 3,
ExpertAdded = 4,
ExpertRemoved = 5,
Notification = 6
ServiceRequest = 6
}
internal enum MtNotificationType
internal enum ServiceRequestType
{
ClientReady = 0
ExpertList = 0
}
internal abstract class MtMessage
@@ -43,16 +43,16 @@
}
}
internal class MtNotification(MtNotificationType notificationType) : MtMessage
internal class MtServiceRequest(ServiceRequestType requestType) : MtMessage
{
public override MessageType MsgType => MessageType.Notification;
public override MessageType MsgType => MessageType.ServiceRequest;
protected override string GetMessageBody()
{
return $"{(int)NotificationType}";
return $"{(int)ServiceRequestType}";
}
public MtNotificationType NotificationType { private set; get; } = notificationType;
public ServiceRequestType ServiceRequestType { private set; get; } = requestType;
}
internal class MtEvent(int expertHandle, int eventType, string payload) : MtMessage
+40 -35
View File
@@ -1,5 +1,4 @@
using System.Diagnostics;
using System.Net.WebSockets;
using System.Net.WebSockets;
using System.Text;
namespace MtClient
@@ -66,9 +65,9 @@ namespace MtClient
logger_.Debug($"MtRpcClient.Disconnect: success");
}
public string? SendCommand(int expertHandle, int commandType, string payload)
public string? SendCommand(int expertHandle, int commandType, string payload, int timeout = 10000) // 10 sec
{
CommandTask commandTask = new();
CommandTask<string> commandTask = new();
int commandId;
lock (tasks_)
{
@@ -79,7 +78,7 @@ namespace MtClient
MtCommand command = new(expertHandle, commandType, commandId, payload);
Send(command);
var response = commandTask.WaitResponse(10000); // 10 sec
var response = commandTask.WaitResponse(timeout);
lock (tasks_)
{
tasks_.Remove(commandId);
@@ -88,10 +87,24 @@ namespace MtClient
return response;
}
public void NotifyClientReady()
public HashSet<int>? RequestExpertsList()
{
MtNotification notification = new(MtNotificationType.ClientReady);
Send(notification);
CommandTask<object> requestTask = new();
lock (service_requests_)
{
service_requests_[ServiceRequestType.ExpertList] = requestTask;
}
MtServiceRequest request = new(ServiceRequestType.ExpertList);
Send(request);
var response = requestTask.WaitResponse(10000); // 10 sec
lock (service_requests_)
{
service_requests_.Remove(ServiceRequestType.ExpertList);
}
return response as HashSet<int>;
}
private void Send(MtMessage message)
@@ -166,30 +179,12 @@ namespace MtClient
else if (result.MessageType == WebSocketMessageType.Text)
{
var msg = Encoding.UTF8.GetString(ms.ToArray(), 0, recvCount);
//var msg = Encoding.ASCII.GetString(recvBuffer, 0, result.Count);
OnReceive(msg);
}
ms.Seek(0, SeekOrigin.Begin);
ms.Position = 0;
}
}
//byte[] recvBuffer = new byte[64 * 1024];
//while (ws_.State == WebSocketState.Open)
//{
// var result = await ws_.ReceiveAsync(new ArraySegment<byte>(recvBuffer), CancellationToken.None);
// if (result.MessageType == WebSocketMessageType.Close)
// {
// logger_.Info($"MtRpcClient.DoReceive: close signal {result.CloseStatusDescription}");
// Disconnected?.Invoke(this, EventArgs.Empty);
// break;
// }
// else
// {
// var msg = Encoding.ASCII.GetString(recvBuffer, 0, result.Count);
// OnReceive(msg);
// }
//}
}
catch (Exception ex)
{
@@ -250,7 +245,7 @@ namespace MtClient
break;
case MessageType.ExpertList:
if (message is MtExpertListMsg expertListMsg)
ExpertList?.Invoke(this, new(expertListMsg.Experts));
ProcessExpertList(expertListMsg.Experts);
break;
case MessageType.ExpertAdded:
if (message is MtExpertAddedMsg expertAddedMsg)
@@ -273,14 +268,24 @@ namespace MtClient
lock (tasks_)
{
if (tasks_.TryGetValue(commandId, out CommandTask? value))
if (tasks_.TryGetValue(commandId, out CommandTask<string>? value))
value.SetResponse(payload);
}
}
private void ProcessExpertList(HashSet<int> experts)
{
logger_.Debug($"MtRpcClient.ProcessExpertList: experts count - {experts.Count}");
lock (service_requests_)
{
if (service_requests_.TryGetValue(ServiceRequestType.ExpertList, out CommandTask<object>? value))
value.SetResponse(experts);
}
}
public event EventHandler<EventArgs>? ConnectionFailed;
public event EventHandler<EventArgs>? Disconnected;
public event EventHandler<MtExpertListEventArgs>? ExpertList;
public event EventHandler<MtExpertEventArgs>? ExpertAdded;
public event EventHandler<MtExpertEventArgs>? ExpertRemoved;
public event EventHandler<MtEventArgs>? MtEventReceived;
@@ -288,7 +293,6 @@ namespace MtClient
private readonly ClientWebSocket ws_ = new();
private readonly string host_;
private readonly int port_;
private readonly byte[] buf_ = new byte[10000];
private readonly Queue<MtMessage> pendingMessages_ = [];
private readonly Thread receiveThread_;
@@ -296,18 +300,19 @@ namespace MtClient
private readonly EventWaitHandle sendWaiter_ = new AutoResetEvent(false);
private int nextCommandId = 0;
private readonly Dictionary<int, CommandTask> tasks_ = [];
private readonly Dictionary<int, CommandTask<string>> tasks_ = [];
private readonly Dictionary<ServiceRequestType, CommandTask<object>> service_requests_ = [];
private readonly IRpcLogger logger_;
}
internal class CommandTask
internal class CommandTask<T>
{
private readonly EventWaitHandle responseWaiter_ = new AutoResetEvent(false);
private string? response_;
private T? response_;
private readonly object locker_ = new();
public string? WaitResponse(int time)
public T? WaitResponse(int time)
{
responseWaiter_.WaitOne(time);
lock (locker_)
@@ -316,7 +321,7 @@ namespace MtClient
}
}
public void SetResponse(string result)
public void SetResponse(T result)
{
lock (locker_)
{
+6
View File
@@ -107,6 +107,12 @@ void MtConnection::OnRead(
return;
}
if (ec == boost::asio::error::eof)
{
log_.Info("%s: %s. Remote peer gracefully closes the connection.", __FUNCTION__, ec.message().c_str());
return;
}
if (ec)
{
log_.Error("%s: %s", __FUNCTION__, ec.message().c_str());
-1
View File
@@ -44,6 +44,5 @@ private:
std::string host_;
std::string read_text_;
boost::beast::flat_buffer read_buffer_;
//std::string send_text_;
std::queue<std::string> send_queue_;
};
+6 -6
View File
@@ -38,7 +38,7 @@ std::unique_ptr<MtCommand> MtCommand::Parse(const std::string& msg)
return command;
}
std::unique_ptr<MtNotification> MtNotification::Parse(const std::string& msg)
std::unique_ptr<MtServiceRequest> MtServiceRequest::Parse(const std::string& msg)
{
std::string::size_type pos = msg.find(';');
@@ -47,17 +47,17 @@ std::unique_ptr<MtNotification> MtNotification::Parse(const std::string& msg)
using rule = qi::rule<std::string::const_iterator>;
std::string message_type;
std::string notification_type;
std::string request_type;
rule_s word_p = qi::as_string[+(qi::char_ - qi::char_(';'))];
rule message_type_p = word_p[boost::phoenix::ref(message_type) = qi::_1];
rule notification_type_p = +qi::char_(';') >> word_p[boost::phoenix::ref(notification_type) = qi::_1];
rule notification_type_p = +qi::char_(';') >> word_p[boost::phoenix::ref(request_type) = qi::_1];
std::unique_ptr<MtNotification> command;
std::unique_ptr<MtServiceRequest> request;
bool ok = qi::parse(msg.begin(), msg.end(), message_type_p >> -notification_type_p);
if (ok)
command = std::make_unique<MtNotification>((NotificationType)std::stoi(notification_type));
request = std::make_unique<MtServiceRequest>((ServiceRequestType)std::stoi(request_type));
return command;
return request;
}
+11 -11
View File
@@ -14,12 +14,12 @@ enum MessageType
EXPERT_LIST = 3,
EXPERT_ADDED = 4,
EXPERT_REMOVED = 5,
NOTIFICATION = 6
SERVICE_REQUEST = 6
};
enum NotificationType
enum ServiceRequestType
{
CLIENT_READY = 0
EXPERTS = 0
};
class MtMessage
@@ -111,25 +111,25 @@ private:
std::string payload_;
};
class MtNotification : public MtMessage
class MtServiceRequest : public MtMessage
{
public:
MtNotification(NotificationType type)
: notification_type_(type)
MtServiceRequest(ServiceRequestType type)
: request_type_(type)
{
}
NotificationType GetNotificationType() const
ServiceRequestType GetServiceRequestType() const
{
return notification_type_;
return request_type_;
}
static std::unique_ptr<MtNotification> Parse(const std::string& msg);
static std::unique_ptr<MtServiceRequest> Parse(const std::string& msg);
private:
MessageType GetType() const override
{
return MessageType::NOTIFICATION;
return MessageType::SERVICE_REQUEST;
}
std::string GetBody() const override
@@ -137,7 +137,7 @@ private:
return "";
}
NotificationType notification_type_;
ServiceRequestType request_type_;
};
class MtEvent : public MtMessage
+5 -5
View File
@@ -288,12 +288,12 @@ void MtServer::ProcessMessage(const std::string& msg, std::weak_ptr<MtConnection
else
log_.Warning("%s: Failed to parse command from message: %s", __FUNCTION__, msg.c_str());
}
else if (msg_type == MessageType::NOTIFICATION)
else if (msg_type == MessageType::SERVICE_REQUEST)
{
auto notification = MtNotification::Parse(msg);
if (notification)
auto request = MtServiceRequest::Parse(msg);
if (request)
{
if (notification->GetNotificationType() == NotificationType::CLIENT_READY)
if (request->GetServiceRequestType() == ServiceRequestType::EXPERTS)
{
std::vector<int> expert_list;
for (const auto& e : experts_)
@@ -306,7 +306,7 @@ void MtServer::ProcessMessage(const std::string& msg, std::weak_ptr<MtConnection
}
}
else
log_.Warning("%s: Failed to parse notification from message: %s", __FUNCTION__, msg.c_str());
log_.Warning("%s: Failed to parse service request from message: %s", __FUNCTION__, msg.c_str());
}
else
{
+1
View File
@@ -1,5 +1,6 @@
#pragma once
#include <string>
#include <thread>
#include <unordered_map>
+36 -16
View File
@@ -166,6 +166,8 @@
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Label Grid.Row="0" Content="Quotes" Background="LightYellow" />
<ListView Grid.Row="1" Margin="2"
@@ -181,6 +183,12 @@
</GridView>
</ListView.View>
</ListView>
<Button Grid.Row="2" Content="Refresh Quotes" Margin="2" Command="{Binding RefreshQuotesCommand}"/>
<StackPanel Grid.Row="3" Orientation="Horizontal" HorizontalAlignment="Left" Margin="2">
<TextBlock Text="Command timeout (ms):" VerticalAlignment="Center" Margin="2"/>
<TextBox Text="{Binding CommandTimeout}" Width="100" Margin="2"/>
<Button Content="Apply" Margin="2" Command="{Binding TimeoutApplyCommand}"/>
</StackPanel>
</Grid>
</Border>
</Grid>
@@ -473,22 +481,34 @@
</TabItem>
<TabItem Header="Market Info">
<WrapPanel VerticalAlignment="Top" Margin="5">
<Button Command="{Binding SymbolsTotalCommand}" Content="SymbolsTotal" Margin="2"/>
<Button Command="{Binding SymbolNameCommand}" Content="SymbolName" Margin="2"/>
<Button Command="{Binding SymbolSelectCommand}" Content="SymbolSelect" Margin="2"/>
<Button Command="{Binding SymbolIsSynchronizedCommand}" Content="SymbolIsSynchronized" Margin="2"/>
<Button Command="{Binding SymbolInfoDoubleCommand}" Content="SymbolInfoDouble" Margin="2"/>
<Button Command="{Binding SymbolInfoIntegerCommand}" Content="SymbolInfoInteger" Margin="2"/>
<Button Command="{Binding SymbolInfoStringCommand}" Content="SymbolInfoString" Margin="2"/>
<Button Command="{Binding SymbolInfoString2Command}" Content="SymbolInfoString-2" Margin="2"/>
<Button Command="{Binding SymbolInfoTickCommand}" Content="SymbolInfoTick" Margin="2"/>
<Button Command="{Binding SymbolInfoSessionQuoteCommand}" Content="SymbolInfoSessionQuote" Margin="2"/>
<Button Command="{Binding SymbolInfoSessionTradeCommand}" Content="SymbolInfoSessionTrade" Margin="2"/>
<Button Command="{Binding MarketBookAddCommand}" Content="MarketBookAdd" Margin="2"/>
<Button Command="{Binding MarketBookReleaseCommand}" Content="MarketBookRelease" Margin="2"/>
<Button Command="{Binding MarketBookGetCommand}" Content="MarketBookGet" Margin="2"/>
</WrapPanel>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<WrapPanel Grid.Row="0" VerticalAlignment="Top" Margin="5">
<Button Command="{Binding SymbolsTotalCommand}" Content="SymbolsTotal" Margin="2"/>
<Button Command="{Binding SymbolNameCommand}" Content="SymbolName" Margin="2"/>
<Button Command="{Binding SymbolSelectCommand}" Content="SymbolSelect" Margin="2"/>
<Button Command="{Binding SymbolIsSynchronizedCommand}" Content="SymbolIsSynchronized" Margin="2"/>
<Button Command="{Binding SymbolInfoDoubleCommand}" Content="SymbolInfoDouble" Margin="2"/>
<Button Command="{Binding SymbolInfoIntegerCommand}" Content="SymbolInfoInteger" Margin="2"/>
<Button Command="{Binding SymbolInfoStringCommand}" Content="SymbolInfoString" Margin="2"/>
<Button Command="{Binding SymbolInfoString2Command}" Content="SymbolInfoString-2" Margin="2"/>
<Button Command="{Binding SymbolInfoTickCommand}" Content="SymbolInfoTick" Margin="2"/>
<Button Command="{Binding SymbolInfoSessionQuoteCommand}" Content="SymbolInfoSessionQuote" Margin="2"/>
<Button Command="{Binding SymbolInfoSessionTradeCommand}" Content="SymbolInfoSessionTrade" Margin="2"/>
<Button Command="{Binding MarketBookAddCommand}" Content="MarketBookAdd" Margin="2"/>
<Button Command="{Binding MarketBookReleaseCommand}" Content="MarketBookRelease" Margin="2"/>
<Button Command="{Binding MarketBookGetCommand}" Content="MarketBookGet" Margin="2"/>
</WrapPanel>
<StackPanel Grid.Row="1" Orientation="Horizontal">
<Button Content="GetSymbols" Command="{Binding GetSymbolsCommand}" Width="100" Margin="2"/>
<CheckBox Content="Selected" IsChecked="{Binding GetSymbolsSelected}" Margin="5" />
</StackPanel>
<ListBox Grid.Row="2" ItemsSource="{Binding Symbols}" Height="Auto" Width="200" HorizontalAlignment="Left"/>
</Grid>
</TabItem>
<TabItem Header="CTrade (Positions)">
+71 -2
View File
@@ -160,6 +160,11 @@ namespace MtApi5TestClient
public DelegateCommand GlobalVariablesTotalCommand { get; private set; }
public DelegateCommand UnlockTicksCommand { get; private set; }
public DelegateCommand GetSymbolsCommand { get; private set; }
public DelegateCommand RefreshQuotesCommand { get; private set; }
public DelegateCommand TimeoutApplyCommand { get; private set; }
#endregion
#region Properties
@@ -207,6 +212,17 @@ namespace MtApi5TestClient
}
}
private int _command_timeout;
public int CommandTimeout
{
get { return _command_timeout; }
set
{
_command_timeout = value;
OnPropertyChanged("CommandTimeout");
}
}
public ObservableCollection<QuoteViewModel> Quotes { get; } = new ObservableCollection<QuoteViewModel>();
private QuoteViewModel _selectedQuote;
@@ -314,6 +330,19 @@ namespace MtApi5TestClient
OnPropertyChanged("PositionTicketValue");
}
}
public bool GetSymbolsSelected { get; set; } = false;
private List<string> _symbols;
public List<string> Symbols
{
get { return _symbols; }
set
{
_symbols = value;
OnPropertyChanged("Symbols");
}
}
#endregion
#region Public Methods
@@ -334,6 +363,7 @@ namespace MtApi5TestClient
ConnectionState = _mtApiClient.ConnectionState;
ConnectionMessage = "Disconnected";
Port = 8228; //default local port
CommandTimeout = _mtApiClient.CommandTimeout;
InitCommands();
@@ -475,6 +505,11 @@ namespace MtApi5TestClient
GlobalVariablesTotalCommand = new DelegateCommand(ExecuteGlobalVariablesTotal);
UnlockTicksCommand = new DelegateCommand(ExecuteUnlockTicks);
GetSymbolsCommand = new DelegateCommand(ExecuteGetSymbols);
RefreshQuotesCommand = new DelegateCommand(ExecuteRefreshQuotes);
TimeoutApplyCommand = new DelegateCommand(ExecuteTimeoutApply);
}
private bool CanExecuteConnect(object o)
@@ -1054,7 +1089,7 @@ namespace MtApi5TestClient
{
foreach (var v in result)
{
var tickStr = $"time = {v.time}, bid = {v.bid}, ask = {v.ask}, last = {v.last}, volume = {v.volume}";
var tickStr = $"time = {v.time}, bid = {v.bid}, ask = {v.ask}, last = {v.last}, volume = {v.volume}, flags = {v.flags}";
TimeSeriesResults.Add(tickStr);
}
});
@@ -1142,6 +1177,7 @@ namespace MtApi5TestClient
AddLog($"SymbolInfoTick(EURUSD) tick.last = {result.last}");
AddLog($"SymbolInfoTick(EURUSD) tick.volume = {result.volume}");
AddLog($"SymbolInfoTick(EURUSD) tick.volume_real = {result.volume_real}");
AddLog($"SymbolInfoTick(EURUSD) tick.flags = {result.flags}");
}
private async void ExecuteSymbolInfoSessionQuote(object o)
@@ -1726,6 +1762,39 @@ namespace MtApi5TestClient
_mtApiClient.UnlockTicks();
}
private async void ExecuteGetSymbols(object o)
{
var result = await Execute(() => _mtApiClient.GetSymbols(GetSymbolsSelected));
if (result == null)
return;
AddLog($"ChartScreenShot: {result.Count} count of symbols");
RunOnUiThread(() =>
{
Symbols = result;
});
}
private async void ExecuteRefreshQuotes(object o)
{
_quotesMap.Clear();
Quotes.Clear();
var quotes = await Execute(() => _mtApiClient.GetQuotes());
if (quotes != null)
{
foreach (var quote in quotes)
{
AddQuote(quote);
}
}
}
private void ExecuteTimeoutApply(object o)
{
_mtApiClient.CommandTimeout = CommandTimeout;
AddLog($"TimeoutApply: timeout = {CommandTimeout} milliseconds");
}
private static void RunOnUiThread(Action action)
{
Application.Current?.Dispatcher.Invoke(action);
@@ -1804,7 +1873,7 @@ namespace MtApi5TestClient
private void _mtApiClient_OnLastTimeBar(object sender, Mt5TimeBarArgs e)
{
AddLog($"OnLastTimeBarEvent: ExpertHandle = {e.ExpertHandle}, Symbol = {e.Symbol}, open = {e.Rates.open}, close = {e.Rates.close}, time = {e.Rates.time}, high = {e.Rates.high}, low = {e.Rates.low}");
AddLog($"OnLastTimeBarEvent: ExpertHandle = {e.ExpertHandle}, Symbol = {e.Symbol}, Timeframe = {e.Timeframe}, open = {e.Rates.open}, close = {e.Rates.close}, time = {e.Rates.time}, high = {e.Rates.high}, low = {e.Rates.low}");
}
private void _mtApiClient_OnLockTicks(object sender, Mt5LockTicksEventArgs e)
File diff suppressed because it is too large Load Diff
+23 -44
View File
@@ -1,51 +1,16 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
using MtApi;
using MtApi;
using MtApi.Monitors;
using System.Globalization;
using System.Runtime.InteropServices;
namespace TestApiClientUI
{
class MtLogger : IMtLogger
{
public void Debug(object message)
{
Write("DEBUG", message);
}
public void Error(object message)
{
Write("ERROR", message);
}
public void Fatal(object message)
{
Write("FATAL", message);
}
public void Info(object message)
{
Write("INFO", message);
}
public void Warn(object message)
{
Write("WARN", message);
}
private void Write(string level, object message)
{
Console.WriteLine($"[{Environment.CurrentManagedThreadId}] [{level}] {message}");
}
}
public partial class Form1 : Form
{
#region Fields
private readonly List<Action> _groupOrderCommands = [];
private readonly MtApiClient _apiClient = new (new MtLogger());
private readonly MtApiClient _apiClient = new(new MtLogger());
private readonly TimerTradeMonitor _timerTradeMonitor;
private readonly TimeframeTradeMonitor _timeframeTradeMonitor;
@@ -742,7 +707,7 @@ namespace TestApiClientUI
var symbol = textBoxOrderSymbol.Text;
var cmd = (TradeOperation) comboBoxOrderCommand.SelectedIndex;
var cmd = (TradeOperation)comboBoxOrderCommand.SelectedIndex;
double volume;
double.TryParse(textBoxOrderVolume.Text, out volume);
@@ -750,7 +715,7 @@ namespace TestApiClientUI
double price;
double.TryParse(textBoxOrderPrice.Text, out price);
var slippage = (int) numericOrderSlippage.Value;
var slippage = (int)numericOrderSlippage.Value;
double stoploss;
double.TryParse(textBoxOrderStoploss.Text, out stoploss);
@@ -805,8 +770,8 @@ namespace TestApiClientUI
private async void button16_Click(object sender, EventArgs e)
{
var ticket = int.Parse(textBoxIndexTicket.Text);
var selectMode = (OrderSelectMode) comboBox1.SelectedIndex;
var selectSource = (OrderSelectSource) comboBox2.SelectedIndex;
var selectMode = (OrderSelectMode)comboBox1.SelectedIndex;
var selectSource = (OrderSelectSource)comboBox2.SelectedIndex;
var order = await Execute(() => _apiClient.GetOrder(ticket, selectMode, selectSource));
@@ -1120,12 +1085,12 @@ namespace TestApiClientUI
{
if (e.Opened != null)
{
PrintLog($"{sender.GetType()}: Opened orders - {string.Join(", ", e.Opened.Select(o => o.Ticket).ToList())}");
PrintLog($"{sender.GetType()}: Opened orders - {string.Join(", ", e.Opened.Select(o => new { o.Ticket, o.Symbol, o.OpenPrice, o.OpenTime }).ToList())}");
}
if (e.Closed != null)
{
PrintLog($"{sender.GetType()}: Closed orders - {string.Join(", ", e.Closed.Select(o => o.Ticket).ToList())}");
PrintLog($"{sender.GetType()}: Closed orders - {string.Join(", ", e.Closed.Select(o => new { o.Ticket, o.Symbol, o.ClosePrice, o.CloseTime }).ToList())}");
}
}
@@ -1544,5 +1509,19 @@ namespace TestApiClientUI
PrintLog($"iBarShift result1 = {result1}, time = {time1}");
PrintLog($"iBarShift result2 = {result2}, time = {time2}");
}
private async void button74_Click(object sender, EventArgs e)
{
listBoxAllSymbols.Items.Clear();
var result = await Execute(() => _apiClient.GetSymbols(checkBox3.Checked));
if (result != null)
{
foreach (string? r in result)
listBoxAllSymbols.Items.Add(r);
}
int count = result != null ? result.Count : 0;
PrintLog($"GetSymbols: {count}");
}
}
}
+36
View File
@@ -0,0 +1,36 @@
using MtApi;
namespace TestApiClientUI
{
class MtLogger : IMtLogger
{
public void Debug(object message)
{
Write("DEBUG", message);
}
public void Error(object message)
{
Write("ERROR", message);
}
public void Fatal(object message)
{
Write("FATAL", message);
}
public void Info(object message)
{
Write("INFO", message);
}
public void Warn(object message)
{
Write("WARN", message);
}
private void Write(string level, object message)
{
Console.WriteLine($"[{Environment.CurrentManagedThreadId}] [{level}] {message}");
}
}
}
BIN
View File
Binary file not shown.
+46 -8
View File
@@ -1330,6 +1330,9 @@ int ExecuteCommand()
case 290: //GetQuote
response = Execute_GetQuote();
break;
case 291: //GetSymbols
response = Execute_GetSymbols();
break;
default:
Print("WARNING: Unknown command type = ", command_type);
@@ -2269,7 +2272,7 @@ string Execute_iBands()
GET_STRING_JSON_VALUE(jo, "Symbol", symbol);
GET_INT_JSON_VALUE(jo, "Timeframe", timeframe);
GET_INT_JSON_VALUE(jo, "Period", period);
GET_INT_JSON_VALUE(jo, "Deviation", deviation);
GET_DOUBLE_JSON_VALUE(jo, "Deviation", deviation);
GET_INT_JSON_VALUE(jo, "BandsShift", bands_shift);
GET_INT_JSON_VALUE(jo, "AppliedPrice", applied_price);
GET_INT_JSON_VALUE(jo, "Mode", mode);
@@ -2284,7 +2287,7 @@ string Execute_iBandsOnArray()
GET_JSON_PAYLOAD(jo);
GET_INT_JSON_VALUE(jo, "Total", total);
GET_INT_JSON_VALUE(jo, "Period", period);
GET_INT_JSON_VALUE(jo, "Deviation", deviation);
GET_DOUBLE_JSON_VALUE(jo, "Deviation", deviation);
GET_INT_JSON_VALUE(jo, "BandsShift", bands_shift);
GET_INT_JSON_VALUE(jo, "Mode", mode);
GET_INT_JSON_VALUE(jo, "Shift", shift);
@@ -3793,15 +3796,24 @@ bool OrderCloseAll()
if (OrderSelect(i, SELECT_BY_POS))
{
int type = OrderType();
bool order_closed = true;
switch(type)
{
//Close opened long positions
case OP_BUY: OrderClose( OrderTicket(), OrderLots(), MarketInfo(OrderSymbol(), MODE_BID), 5, Red );
case OP_BUY:
{
order_closed = OrderClose( OrderTicket(), OrderLots(), MarketInfo(OrderSymbol(), MODE_BID), 5, Red );
break;
}
//Close opened short positions
case OP_SELL: OrderClose( OrderTicket(), OrderLots(), MarketInfo(OrderSymbol(), MODE_ASK), 5, Red );
case OP_SELL:
{
order_closed = OrderClose( OrderTicket(), OrderLots(), MarketInfo(OrderSymbol(), MODE_ASK), 5, Red );
break;
}
}
if (order_closed == false)
Print("Failed to close order ", OrderTicket());
}
}
@@ -3961,10 +3973,8 @@ string Execute_iCustom()
{
int intParams[];
ArrayResize(intParams, size);
for (int i = 0; i < size; i++)
{
intParams[i] = jaParams.getInt(i);
}
for (int it_i = 0; it_i < size; it_i++)
intParams[it_i] = jaParams.getInt(it_i);
result = iCustomT(symbol, timeframe, name, intParams, size, mode, shift);
}
break;
@@ -3972,6 +3982,8 @@ string Execute_iCustom()
{
double doubleParams[];
ArrayResize(doubleParams, size);
for (int it_d = 0; it_d < size; it_d++)
doubleParams[it_d] = jaParams.getDouble(it_d);
result = iCustomT(symbol, timeframe, name, doubleParams, size, mode, shift);
}
break;
@@ -3979,6 +3991,8 @@ string Execute_iCustom()
{
string stringParams[];
ArrayResize(stringParams, size);
for (int it_s = 0; it_s < size; it_s++)
stringParams[it_s] = jaParams.getString(it_s);
result = iCustomT(symbol, timeframe, name, stringParams, size, mode, shift);
}
break;
@@ -3986,6 +4000,8 @@ string Execute_iCustom()
{
bool boolParams[];
ArrayResize(boolParams, size);
for (int it_b = 0; it_b < size; it_b++)
boolParams[it_b] = jaParams.getBool(it_b);
result = iCustomT(symbol, timeframe, name, boolParams, size, mode, shift);
}
break;
@@ -4183,3 +4199,25 @@ string Execute_GetQuote()
MtQuote quote(Symbol(), tick);
return CreateSuccessResponse(quote.CreateJson());
}
string Execute_GetSymbols()
{
GET_JSON_PAYLOAD(jo);
GET_BOOL_JSON_VALUE(jo, "Selected", selected);
const int symbolsCount = SymbolsTotal(selected);
JSONArray* jaSymbols = new JSONArray();
int idx = 0;
for(int idxSymbol = 0; idxSymbol < symbolsCount; idxSymbol++)
{
string symbol = SymbolName(idxSymbol, selected);
string firstChar = StringSubstr(symbol, 0, 1);
if(firstChar != "#" && StringLen(symbol) == 6)
{
jaSymbols.put(idx, new JSONString(symbol));
idx++;
}
}
return CreateSuccessResponse(jaSymbols);
}
Regular → Executable
BIN
View File
Binary file not shown.
+60 -13
View File
@@ -1,7 +1,7 @@
#property copyright "Vyacheslav Demidyuk"
#property link ""
#property version "2.0"
#property version "2.1"
#property description "MtApi (MT5) connection expert"
#include <json.mqh>
@@ -82,7 +82,7 @@ void OnTick()
MqlRates rates_array[];
CopyRates(symbol, Period(), 1, 1, rates_array);
MtTimeBarEvent time_bar(symbol, rates_array[0]);
MtTimeBarEvent time_bar(symbol, (int)Period(), rates_array[0]);
SendMtEvent(ON_LAST_TIME_BAR_EVENT, time_bar);
}
lastbar_time_changed = true;
@@ -380,6 +380,7 @@ int preinit()
ADD_EXECUTOR(303, OrderCheck);
ADD_EXECUTOR(304, Buy);
ADD_EXECUTOR(305, Sell);
ADD_EXECUTOR(306, GetSymbols);
return (0);
}
@@ -408,14 +409,14 @@ int init()
isCrashed = true;
return (1);
}
if (MQL5InfoInteger(MQL5_DLLS_ALLOWED) == false)
if (MQLInfoInteger(MQL_DLLS_ALLOWED) == false)
{
MessageBox("Libraries not allowed.", "MtApi", 0);
isCrashed = true;
return (1);
}
if (MQL5InfoInteger(MQL5_TRADE_ALLOWED) == false)
if (MQLInfoInteger(MQL_TRADE_ALLOWED) == false)
{
MessageBox("Trade not allowed.", "MtApi", 0);
isCrashed = true;
@@ -1829,7 +1830,7 @@ string Execute_ObjectCreate()
datetime times[30];
double prices[30];
ArrayInitialize(times, EMPTY_VALUE);
ArrayInitialize(times, 0);
ArrayInitialize(prices, EMPTY_VALUE);
JSONArray* times_jo = jo.p.getArray("Times");
@@ -2168,10 +2169,10 @@ string Execute_iChaikin()
GET_INT_JSON_VALUE(jo, "Period", period);
GET_INT_JSON_VALUE(jo, "FastMaPeriod", fast_ma_period);
GET_INT_JSON_VALUE(jo, "SlowMaPeriod", slow_ma_period);
GET_INT_JSON_VALUE(jo, "MaPeriod", ma_period);
GET_INT_JSON_VALUE(jo, "MaMethod", ma_method);
GET_INT_JSON_VALUE(jo, "AppliedVolume", applied_volume);
int result = iChaikin(symbol, (ENUM_TIMEFRAMES)period, fast_ma_period, slow_ma_period, (ENUM_MA_METHOD)ma_period, (ENUM_APPLIED_VOLUME) applied_volume);
int result = iChaikin(symbol, (ENUM_TIMEFRAMES)period, fast_ma_period, slow_ma_period, (ENUM_MA_METHOD)ma_method, (ENUM_APPLIED_VOLUME) applied_volume);
return CreateSuccessResponse(new JSONNumber(result));
}
@@ -2377,7 +2378,7 @@ string Execute_iSAR()
GET_STRING_JSON_VALUE(jo, "Symbol", symbol);
GET_INT_JSON_VALUE(jo, "Period", period);
GET_DOUBLE_JSON_VALUE(jo, "Step", step);
GET_DOUBLE_JSON_VALUE(jo, "Mamimum", maximum);
GET_DOUBLE_JSON_VALUE(jo, "Maximum", maximum);
int result = iSAR(symbol, (ENUM_TIMEFRAMES)period, step, maximum);
return CreateSuccessResponse(new JSONNumber(result));
@@ -2959,6 +2960,7 @@ string Execute_UnlockTicks()
return CreateErrorResponse(-1, "UnlockTicks can be used only for backtesting");
}
_is_ticks_locked = false;
return CreateSuccessResponse();
}
@@ -3065,15 +3067,15 @@ string Execute_iCustom()
int intParams[];
ArrayResize(intParams, size);
for (int i = 0; i < size; i++)
{
intParams[i] = jaParams.getInt(i);
}
result = iCustomT(symbol, (ENUM_TIMEFRAMES)timeframe, name, intParams, size);
}
break;
case 1: //Double
{
int doubleParams[];
double doubleParams[];
for (int i = 0; i < size; i++)
doubleParams[i] = jaParams.getDouble(i);
ArrayResize(doubleParams, size);
result = iCustomT(symbol, (ENUM_TIMEFRAMES)timeframe, name, doubleParams, size);
}
@@ -3082,13 +3084,17 @@ string Execute_iCustom()
{
string stringParams[];
ArrayResize(stringParams, size);
for (int i = 0; i < size; i++)
stringParams[i] = jaParams.getString(i);
result = iCustomT(symbol, (ENUM_TIMEFRAMES)timeframe, name, stringParams, size);
}
break;
case 3: //Boolean
{
string boolParams[];
bool boolParams[];
ArrayResize(boolParams, size);
for (int i = 0; i < size; i++)
boolParams[i] = jaParams.getBool(i);
result = iCustomT(symbol, (ENUM_TIMEFRAMES)timeframe, name, boolParams, size);
}
break;
@@ -3446,6 +3452,28 @@ string Execute_Sell()
return CreateSuccessResponse(result_value_jo);
}
string Execute_GetSymbols()
{
GET_JSON_PAYLOAD(jo);
GET_BOOL_JSON_VALUE(jo, "Selected", selected);
const int symbolsCount = SymbolsTotal(selected);
JSONArray* jaSymbols = new JSONArray();
int idx = 0;
for(int idxSymbol = 0; idxSymbol < symbolsCount; idxSymbol++)
{
string symbol = SymbolName(idxSymbol, selected);
string firstChar = StringSubstr(symbol, 0, 1);
if(firstChar != "#" && StringLen(symbol) == 6)
{
jaSymbols.put(idx, new JSONString(symbol));
idx++;
}
}
return CreateSuccessResponse(jaSymbols);
}
int PositionCloseAll()
{
CTrade trade;
@@ -3635,9 +3663,10 @@ private:
class MtTimeBarEvent: public MtObject
{
public:
MtTimeBarEvent(string symbol, const MqlRates& rates)
MtTimeBarEvent(string symbol, int timeframe, const MqlRates& rates)
{
_symbol = symbol;
_timeframe = timeframe;
_rates = rates;
}
@@ -3646,12 +3675,14 @@ public:
JSONObject *jo = new JSONObject();
jo.put("Rates", MqlRatesToJson(_rates));
jo.put("Instrument", new JSONString(_symbol));
jo.put("Timeframe", new JSONNumber(_timeframe));
jo.put("ExpertHandle", new JSONNumber(ExpertHandle));
return jo;
}
private:
string _symbol;
int _timeframe;
MqlRates _rates;
};
@@ -3774,6 +3805,21 @@ bool JsonToMqlTradeRequest(JSONObject *jo, MqlTradeRequest& request)
JSONObject* MqlTickToJson(const MqlTick& tick)
{
// MT5 can add some additional non-documented flags, so we need to filter required documented flags only
int summ=0;
if((tick.flags & TICK_FLAG_BID)==TICK_FLAG_BID)
summ+=TICK_FLAG_BID;
if((tick.flags & TICK_FLAG_ASK)==TICK_FLAG_ASK)
summ+=TICK_FLAG_ASK;
if((tick.flags & TICK_FLAG_LAST)==TICK_FLAG_LAST)
summ+=TICK_FLAG_LAST;
if((tick.flags & TICK_FLAG_VOLUME)==TICK_FLAG_VOLUME)
summ+=TICK_FLAG_VOLUME;
if((tick.flags & TICK_FLAG_BUY)==TICK_FLAG_BUY)
summ+=TICK_FLAG_BUY;
if((tick.flags & TICK_FLAG_SELL)==TICK_FLAG_SELL)
summ+=TICK_FLAG_SELL;
JSONObject *jo = new JSONObject();
jo.put("Time", new JSONNumber((long)tick.time));
jo.put("Bid", new JSONNumber(tick.bid));
@@ -3781,6 +3827,7 @@ JSONObject* MqlTickToJson(const MqlTick& tick)
jo.put("Last", new JSONNumber(tick.last));
jo.put("Volume", new JSONNumber(tick.volume));
jo.put("VolumeReal", new JSONNumber(tick.volume_real));
jo.put("Flags", new JSONNumber(summ));
return jo;
}
+10 -10
View File
@@ -324,27 +324,27 @@ public:
/// Lookup key and get associated string value, return false if failure.
bool getString(string key,string &out)
{
return getString(getValue(key),out);
return JSONValue::getString(getValue(key),out);
}
/// Lookup key and get associated bool value, return false if failure.
bool getBool(string key,bool &out)
{
return getBool(getValue(key),out);
return JSONValue::getBool(getValue(key),out);
}
/// Lookup key and get associated double value, return false if failure.
bool getDouble(string key,double &out)
{
return getDouble(getValue(key),out);
return JSONValue::getDouble(getValue(key),out);
}
/// Lookup key and get associated long value, return false if failure.
bool getLong(string key,long &out)
{
return getLong(getValue(key),out);
return JSONValue::getLong(getValue(key),out);
}
/// Lookup key and get associated int value, return false if failure.
bool getInt(string key,int &out)
{
return getInt(getValue(key),out);
return JSONValue::getInt(getValue(key),out);
}
/// Lookup key and get associated array, NULL if not present. Cast failure if not an Array.
@@ -451,27 +451,27 @@ public:
/// Lookup JSONString by array index. NULL if not present. Cast failure if not an Object.
bool getString(int index,string &out)
{
return getString(getValue(index),out);
return JSONValue::getString(getValue(index),out);
}
/// Lookup JSONBool by array index. NULL if not present. Cast failure if not an Object.
bool getBool(int index,bool &out)
{
return getBool(getValue(index),out);
return JSONValue::getBool(getValue(index),out);
}
/// Lookup JSONNumber by array index. NULL if not present. Cast failure if not an Object.
bool getDouble(int index,double &out)
{
return getDouble(getValue(index),out);
return JSONValue::getDouble(getValue(index),out);
}
/// Lookup JSONNumber by array index. NULL if not present. Cast failure if not an Object.
bool getLong(int index,long &out)
{
return getLong(getValue(index),out);
return JSONValue::getLong(getValue(index),out);
}
/// Lookup JSONNumber by array index. NULL if not present. Cast failure if not an Object.
bool getInt(int index,int &out)
{
return getInt(getValue(index),out);
return JSONValue::getInt(getValue(index),out);
}
/// Lookup array child by index, NULL if not present. Cast failure if not an Array.
+35
View File
@@ -0,0 +1,35 @@
// Boost.Bimap
//
// Copyright (c) 2006-2007 Matias Capeletto
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
/// \file detail/debug/static_error.hpp
/// \brief Formatted compile time error
#ifndef BOOST_BIMAP_DETAIL_DEBUG_STATIC_ERROR_HPP
#define BOOST_BIMAP_DETAIL_DEBUG_STATIC_ERROR_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/preprocessor/cat.hpp>
// Easier way to call BOOST_MPL_ASSERT_MSG in class scope to generate
// a static error.
/*===========================================================================*/
#define BOOST_BIMAP_STATIC_ERROR(MESSAGE,VARIABLES) \
BOOST_MPL_ASSERT_MSG(false, \
BOOST_PP_CAT(BIMAP_STATIC_ERROR__,MESSAGE), \
VARIABLES)
/*===========================================================================*/
#endif // BOOST_BIMAP_DETAIL_DEBUG_STATIC_ERROR_HPP
+93
View File
@@ -0,0 +1,93 @@
/*
Copyright Rene Rivera 2008-2015
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef BOOST_PREDEF_ARCHITECTURE_X86_32_H
#define BOOST_PREDEF_ARCHITECTURE_X86_32_H
#include <boost/predef/version_number.h>
#include <boost/predef/make.h>
/* tag::reference[]
= `BOOST_ARCH_X86_32`
http://en.wikipedia.org/wiki/X86[Intel x86] architecture:
If available versions [3-6] are specifically detected.
[options="header"]
|===
| {predef_symbol} | {predef_version}
| `i386` | {predef_detection}
| `+__i386__+` | {predef_detection}
| `+__i486__+` | {predef_detection}
| `+__i586__+` | {predef_detection}
| `+__i686__+` | {predef_detection}
| `+__i386+` | {predef_detection}
| `+_M_IX86+` | {predef_detection}
| `+_X86_+` | {predef_detection}
| `+__THW_INTEL__+` | {predef_detection}
| `+__I86__+` | {predef_detection}
| `+__INTEL__+` | {predef_detection}
| `+__I86__+` | V.0.0
| `+_M_IX86+` | V.0.0
| `+__i686__+` | 6.0.0
| `+__i586__+` | 5.0.0
| `+__i486__+` | 4.0.0
| `+__i386__+` | 3.0.0
|===
*/ // end::reference[]
#define BOOST_ARCH_X86_32 BOOST_VERSION_NUMBER_NOT_AVAILABLE
#if defined(i386) || defined(__i386__) || \
defined(__i486__) || defined(__i586__) || \
defined(__i686__) || defined(__i386) || \
defined(_M_IX86) || defined(_X86_) || \
defined(__THW_INTEL__) || defined(__I86__) || \
defined(__INTEL__)
# undef BOOST_ARCH_X86_32
# if !defined(BOOST_ARCH_X86_32) && defined(__I86__)
# define BOOST_ARCH_X86_32 BOOST_VERSION_NUMBER(__I86__,0,0)
# endif
# if !defined(BOOST_ARCH_X86_32) && defined(_M_IX86)
# define BOOST_ARCH_X86_32 BOOST_PREDEF_MAKE_10_VV00(_M_IX86)
# endif
# if !defined(BOOST_ARCH_X86_32) && defined(__i686__)
# define BOOST_ARCH_X86_32 BOOST_VERSION_NUMBER(6,0,0)
# endif
# if !defined(BOOST_ARCH_X86_32) && defined(__i586__)
# define BOOST_ARCH_X86_32 BOOST_VERSION_NUMBER(5,0,0)
# endif
# if !defined(BOOST_ARCH_X86_32) && defined(__i486__)
# define BOOST_ARCH_X86_32 BOOST_VERSION_NUMBER(4,0,0)
# endif
# if !defined(BOOST_ARCH_X86_32) && defined(__i386__)
# define BOOST_ARCH_X86_32 BOOST_VERSION_NUMBER(3,0,0)
# endif
# if !defined(BOOST_ARCH_X86_32)
# define BOOST_ARCH_X86_32 BOOST_VERSION_NUMBER_AVAILABLE
# endif
#endif
#if BOOST_ARCH_X86_32
# define BOOST_ARCH_X86_32_AVAILABLE
#endif
#if BOOST_ARCH_X86_32
# undef BOOST_ARCH_WORD_BITS_32
# define BOOST_ARCH_WORD_BITS_32 BOOST_VERSION_NUMBER_AVAILABLE
#endif
#define BOOST_ARCH_X86_32_NAME "Intel x86-32"
#include <boost/predef/architecture/x86.h>
#endif
#include <boost/predef/detail/test.h>
BOOST_PREDEF_DECLARE_TEST(BOOST_ARCH_X86_32,BOOST_ARCH_X86_32_NAME)
+56
View File
@@ -0,0 +1,56 @@
/*
Copyright Rene Rivera 2008-2021
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef BOOST_PREDEF_ARCHITECTURE_X86_64_H
#define BOOST_PREDEF_ARCHITECTURE_X86_64_H
#include <boost/predef/version_number.h>
#include <boost/predef/make.h>
/* tag::reference[]
= `BOOST_ARCH_X86_64`
https://en.wikipedia.org/wiki/X86-64[X86-64] architecture.
[options="header"]
|===
| {predef_symbol} | {predef_version}
| `+__x86_64+` | {predef_detection}
| `+__x86_64__+` | {predef_detection}
| `+__amd64__+` | {predef_detection}
| `+__amd64+` | {predef_detection}
| `+_M_X64+` | {predef_detection}
|===
*/ // end::reference[]
#define BOOST_ARCH_X86_64 BOOST_VERSION_NUMBER_NOT_AVAILABLE
#if defined(__x86_64) || defined(__x86_64__) || \
defined(__amd64__) || defined(__amd64) || \
defined(_M_X64)
# undef BOOST_ARCH_X86_64
# define BOOST_ARCH_X86_64 BOOST_VERSION_NUMBER_AVAILABLE
#endif
#if BOOST_ARCH_X86_64
# define BOOST_ARCH_X86_64_AVAILABLE
#endif
#if BOOST_ARCH_X86_64
# undef BOOST_ARCH_WORD_BITS_64
# define BOOST_ARCH_WORD_BITS_64 BOOST_VERSION_NUMBER_AVAILABLE
#endif
#define BOOST_ARCH_X86_64_NAME "Intel x86-64"
#include <boost/predef/architecture/x86.h>
#endif
#include <boost/predef/detail/test.h>
BOOST_PREDEF_DECLARE_TEST(BOOST_ARCH_X86_64,BOOST_ARCH_X86_64_NAME)
+135
View File
@@ -0,0 +1,135 @@
/*
Copyright Charly Chevalier 2015
Copyright Joel Falcou 2015
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef BOOST_PREDEF_HARDWARE_SIMD_X86_VERSIONS_H
#define BOOST_PREDEF_HARDWARE_SIMD_X86_VERSIONS_H
#include <boost/predef/version_number.h>
/* tag::reference[]
= `BOOST_HW_SIMD_X86_*_VERSION`
Those defines represent x86 SIMD extensions versions.
NOTE: You *MUST* compare them with the predef `BOOST_HW_SIMD_X86`.
*/ // end::reference[]
// ---------------------------------
/* tag::reference[]
= `BOOST_HW_SIMD_X86_MMX_VERSION`
The https://en.wikipedia.org/wiki/MMX_(instruction_set)[MMX] x86 extension
version number.
Version number is: *0.99.0*.
*/ // end::reference[]
#define BOOST_HW_SIMD_X86_MMX_VERSION BOOST_VERSION_NUMBER(0, 99, 0)
/* tag::reference[]
= `BOOST_HW_SIMD_X86_SSE_VERSION`
The https://en.wikipedia.org/wiki/Streaming_SIMD_Extensions[SSE] x86 extension
version number.
Version number is: *1.0.0*.
*/ // end::reference[]
#define BOOST_HW_SIMD_X86_SSE_VERSION BOOST_VERSION_NUMBER(1, 0, 0)
/* tag::reference[]
= `BOOST_HW_SIMD_X86_SSE2_VERSION`
The https://en.wikipedia.org/wiki/SSE2[SSE2] x86 extension version number.
Version number is: *2.0.0*.
*/ // end::reference[]
#define BOOST_HW_SIMD_X86_SSE2_VERSION BOOST_VERSION_NUMBER(2, 0, 0)
/* tag::reference[]
= `BOOST_HW_SIMD_X86_SSE3_VERSION`
The https://en.wikipedia.org/wiki/SSE3[SSE3] x86 extension version number.
Version number is: *3.0.0*.
*/ // end::reference[]
#define BOOST_HW_SIMD_X86_SSE3_VERSION BOOST_VERSION_NUMBER(3, 0, 0)
/* tag::reference[]
= `BOOST_HW_SIMD_X86_SSSE3_VERSION`
The https://en.wikipedia.org/wiki/SSSE3[SSSE3] x86 extension version number.
Version number is: *3.1.0*.
*/ // end::reference[]
#define BOOST_HW_SIMD_X86_SSSE3_VERSION BOOST_VERSION_NUMBER(3, 1, 0)
/* tag::reference[]
= `BOOST_HW_SIMD_X86_SSE4_1_VERSION`
The https://en.wikipedia.org/wiki/SSE4#SSE4.1[SSE4_1] x86 extension version
number.
Version number is: *4.1.0*.
*/ // end::reference[]
#define BOOST_HW_SIMD_X86_SSE4_1_VERSION BOOST_VERSION_NUMBER(4, 1, 0)
/* tag::reference[]
= `BOOST_HW_SIMD_X86_SSE4_2_VERSION`
The https://en.wikipedia.org/wiki/SSE4##SSE4.2[SSE4_2] x86 extension version
number.
Version number is: *4.2.0*.
*/ // end::reference[]
#define BOOST_HW_SIMD_X86_SSE4_2_VERSION BOOST_VERSION_NUMBER(4, 2, 0)
/* tag::reference[]
= `BOOST_HW_SIMD_X86_AVX_VERSION`
The https://en.wikipedia.org/wiki/Advanced_Vector_Extensions[AVX] x86
extension version number.
Version number is: *5.0.0*.
*/ // end::reference[]
#define BOOST_HW_SIMD_X86_AVX_VERSION BOOST_VERSION_NUMBER(5, 0, 0)
/* tag::reference[]
= `BOOST_HW_SIMD_X86_FMA3_VERSION`
The https://en.wikipedia.org/wiki/FMA_instruction_set[FMA3] x86 extension
version number.
Version number is: *5.2.0*.
*/ // end::reference[]
#define BOOST_HW_SIMD_X86_FMA3_VERSION BOOST_VERSION_NUMBER(5, 2, 0)
/* tag::reference[]
= `BOOST_HW_SIMD_X86_AVX2_VERSION`
The https://en.wikipedia.org/wiki/Advanced_Vector_Extensions#Advanced_Vector_Extensions_2[AVX2]
x86 extension version number.
Version number is: *5.3.0*.
*/ // end::reference[]
#define BOOST_HW_SIMD_X86_AVX2_VERSION BOOST_VERSION_NUMBER(5, 3, 0)
/* tag::reference[]
= `BOOST_HW_SIMD_X86_MIC_VERSION`
The https://en.wikipedia.org/wiki/Xeon_Phi[MIC] (Xeon Phi) x86 extension
version number.
Version number is: *9.0.0*.
*/ // end::reference[]
#define BOOST_HW_SIMD_X86_MIC_VERSION BOOST_VERSION_NUMBER(9, 0, 0)
/* tag::reference[]
*/ // end::reference[]
#endif
+44
View File
@@ -0,0 +1,44 @@
# /* Copyright (C) 2001
# * Housemarque Oy
# * http://www.housemarque.com
# *
# * Distributed under the Boost Software License, Version 1.0. (See
# * accompanying file LICENSE_1_0.txt or copy at
# * http://www.boost.org/LICENSE_1_0.txt)
# */
#
# /* Revised by Paul Mensonides (2002) */
#
# /* See http://www.boost.org for most recent version. */
#
# ifndef BOOST_PREPROCESSOR_DEBUG_ASSERT_HPP
# define BOOST_PREPROCESSOR_DEBUG_ASSERT_HPP
#
# include <boost/preprocessor/config/config.hpp>
# include <boost/preprocessor/control/expr_iif.hpp>
# include <boost/preprocessor/control/iif.hpp>
# include <boost/preprocessor/logical/not.hpp>
# include <boost/preprocessor/tuple/eat.hpp>
#
# /* BOOST_PP_ASSERT */
#
# if ~BOOST_PP_CONFIG_FLAGS() & BOOST_PP_CONFIG_EDG()
# define BOOST_PP_ASSERT BOOST_PP_ASSERT_D
# else
# define BOOST_PP_ASSERT(cond) BOOST_PP_ASSERT_D(cond)
# endif
#
# define BOOST_PP_ASSERT_D(cond) BOOST_PP_IIF(BOOST_PP_NOT(cond), BOOST_PP_ASSERT_ERROR, BOOST_PP_TUPLE_EAT_1)(...)
# define BOOST_PP_ASSERT_ERROR(x, y, z)
#
# /* BOOST_PP_ASSERT_MSG */
#
# if ~BOOST_PP_CONFIG_FLAGS() & BOOST_PP_CONFIG_EDG()
# define BOOST_PP_ASSERT_MSG BOOST_PP_ASSERT_MSG_D
# else
# define BOOST_PP_ASSERT_MSG(cond, msg) BOOST_PP_ASSERT_MSG_D(cond, msg)
# endif
#
# define BOOST_PP_ASSERT_MSG_D(cond, msg) BOOST_PP_EXPR_IIF(BOOST_PP_NOT(cond), msg)
#
# endif
+33
View File
@@ -0,0 +1,33 @@
# /* **************************************************************************
# * *
# * (C) Copyright Paul Mensonides 2002.
# * Distributed under the Boost Software License, Version 1.0. (See
# * accompanying file LICENSE_1_0.txt or copy at
# * http://www.boost.org/LICENSE_1_0.txt)
# * *
# ************************************************************************** */
#
# /* See http://www.boost.org for most recent version. */
#
# ifndef BOOST_PREPROCESSOR_DEBUG_ERROR_HPP
# define BOOST_PREPROCESSOR_DEBUG_ERROR_HPP
#
# include <boost/preprocessor/cat.hpp>
# include <boost/preprocessor/config/config.hpp>
#
# /* BOOST_PP_ERROR */
#
# if BOOST_PP_CONFIG_ERRORS
# define BOOST_PP_ERROR(code) BOOST_PP_CAT(BOOST_PP_ERROR_, code)
# endif
#
# define BOOST_PP_ERROR_0x0000 BOOST_PP_ERROR(0x0000, BOOST_PP_INDEX_OUT_OF_BOUNDS)
# define BOOST_PP_ERROR_0x0001 BOOST_PP_ERROR(0x0001, BOOST_PP_WHILE_OVERFLOW)
# define BOOST_PP_ERROR_0x0002 BOOST_PP_ERROR(0x0002, BOOST_PP_FOR_OVERFLOW)
# define BOOST_PP_ERROR_0x0003 BOOST_PP_ERROR(0x0003, BOOST_PP_REPEAT_OVERFLOW)
# define BOOST_PP_ERROR_0x0004 BOOST_PP_ERROR(0x0004, BOOST_PP_LIST_FOLD_OVERFLOW)
# define BOOST_PP_ERROR_0x0005 BOOST_PP_ERROR(0x0005, BOOST_PP_SEQ_FOLD_OVERFLOW)
# define BOOST_PP_ERROR_0x0006 BOOST_PP_ERROR(0x0006, BOOST_PP_ARITHMETIC_OVERFLOW)
# define BOOST_PP_ERROR_0x0007 BOOST_PP_ERROR(0x0007, BOOST_PP_DIVISION_BY_ZERO)
#
# endif
+35
View File
@@ -0,0 +1,35 @@
# /* **************************************************************************
# * *
# * (C) Copyright Paul Mensonides 2002.
# * Distributed under the Boost Software License, Version 1.0. (See
# * accompanying file LICENSE_1_0.txt or copy at
# * http://www.boost.org/LICENSE_1_0.txt)
# * *
# ************************************************************************** */
#
# /* See http://www.boost.org for most recent version. */
#
# ifndef BOOST_PREPROCESSOR_DEBUG_LINE_HPP
# define BOOST_PREPROCESSOR_DEBUG_LINE_HPP
#
# include <boost/preprocessor/cat.hpp>
# include <boost/preprocessor/config/config.hpp>
# include <boost/preprocessor/iteration/iterate.hpp>
# include <boost/preprocessor/stringize.hpp>
#
# /* BOOST_PP_LINE */
#
# if BOOST_PP_CONFIG_EXTENDED_LINE_INFO
# define BOOST_PP_LINE(line, file) line BOOST_PP_CAT(BOOST_PP_LINE_, BOOST_PP_IS_ITERATING)(file)
# define BOOST_PP_LINE_BOOST_PP_IS_ITERATING(file) #file
# define BOOST_PP_LINE_1(file) BOOST_PP_STRINGIZE(file BOOST_PP_CAT(BOOST_PP_LINE_I_, BOOST_PP_ITERATION_DEPTH())())
# define BOOST_PP_LINE_I_1() [BOOST_PP_FRAME_ITERATION(1)]
# define BOOST_PP_LINE_I_2() BOOST_PP_LINE_I_1()[BOOST_PP_FRAME_ITERATION(2)]
# define BOOST_PP_LINE_I_3() BOOST_PP_LINE_I_2()[BOOST_PP_FRAME_ITERATION(3)]
# define BOOST_PP_LINE_I_4() BOOST_PP_LINE_I_3()[BOOST_PP_FRAME_ITERATION(4)]
# define BOOST_PP_LINE_I_5() BOOST_PP_LINE_I_4()[BOOST_PP_FRAME_ITERATION(5)]
# else
# define BOOST_PP_LINE(line, file) line __FILE__
# endif
#
# endif
+319
View File
@@ -0,0 +1,319 @@
/*=============================================================================
Copyright (c) 2001-2003 Joel de Guzman
Copyright (c) 2002-2003 Hartmut Kaiser
Copyright (c) 2003 Gustavo Guerra
http://spirit.sourceforge.net/
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
=============================================================================*/
#if !defined(BOOST_SPIRIT_DEBUG_NODE_HPP)
#define BOOST_SPIRIT_DEBUG_NODE_HPP
#if !defined(BOOST_SPIRIT_DEBUG_MAIN_HPP)
#error "You must include boost/spirit/debug.hpp, not boost/spirit/debug/debug_node.hpp"
#endif
#if defined(BOOST_SPIRIT_DEBUG)
#include <string>
#include <boost/type_traits/is_convertible.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/and.hpp>
#include <boost/spirit/home/classic/namespace.hpp>
#include <boost/spirit/home/classic/core/primitives/primitives.hpp> // for iscntrl_
namespace boost { namespace spirit {
BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN
///////////////////////////////////////////////////////////////////////////////
//
// Debug helper classes for rules, which ensure maximum non-intrusiveness of
// the Spirit debug support
//
///////////////////////////////////////////////////////////////////////////////
namespace impl {
struct token_printer_aux_for_chars
{
template<typename CharT>
static void print(std::ostream& o, CharT c)
{
if (c == static_cast<CharT>('\a'))
o << "\\a";
else if (c == static_cast<CharT>('\b'))
o << "\\b";
else if (c == static_cast<CharT>('\f'))
o << "\\f";
else if (c == static_cast<CharT>('\n'))
o << "\\n";
else if (c == static_cast<CharT>('\r'))
o << "\\r";
else if (c == static_cast<CharT>('\t'))
o << "\\t";
else if (c == static_cast<CharT>('\v'))
o << "\\v";
else if (iscntrl_(c))
o << "\\" << static_cast<int>(c);
else
o << static_cast<char>(c);
}
};
// for token types where the comparison with char constants wouldn't work
struct token_printer_aux_for_other_types
{
template<typename CharT>
static void print(std::ostream& o, CharT c)
{
o << c;
}
};
template <typename CharT>
struct token_printer_aux
: mpl::if_<
mpl::and_<
is_convertible<CharT, char>,
is_convertible<char, CharT> >,
token_printer_aux_for_chars,
token_printer_aux_for_other_types
>::type
{
};
template<typename CharT>
inline void token_printer(std::ostream& o, CharT c)
{
#if !defined(BOOST_SPIRIT_DEBUG_TOKEN_PRINTER)
token_printer_aux<CharT>::print(o, c);
#else
BOOST_SPIRIT_DEBUG_TOKEN_PRINTER(o, c);
#endif
}
///////////////////////////////////////////////////////////////////////////////
//
// Dump infos about the parsing state of a rule
//
///////////////////////////////////////////////////////////////////////////////
#if BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES
template <typename IteratorT>
inline void
print_node_info(bool hit, int level, bool close, std::string const& name,
IteratorT first, IteratorT last)
{
if (!name.empty())
{
for (int i = 0; i < level; ++i)
BOOST_SPIRIT_DEBUG_OUT << " ";
if (close)
{
if (hit)
BOOST_SPIRIT_DEBUG_OUT << "/";
else
BOOST_SPIRIT_DEBUG_OUT << "#";
}
BOOST_SPIRIT_DEBUG_OUT << name << ":\t\"";
IteratorT iter = first;
IteratorT ilast = last;
for (int j = 0; j < BOOST_SPIRIT_DEBUG_PRINT_SOME; ++j)
{
if (iter == ilast)
break;
token_printer(BOOST_SPIRIT_DEBUG_OUT, *iter);
++iter;
}
BOOST_SPIRIT_DEBUG_OUT << "\"\n";
}
}
#endif // BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES
#if BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_CLOSURES
template <typename ResultT>
inline ResultT &
print_closure_info(ResultT &hit, int level, std::string const& name)
{
if (!name.empty())
{
for (int i = 0; i < level-1; ++i)
BOOST_SPIRIT_DEBUG_OUT << " ";
// for now, print out the return value only
BOOST_SPIRIT_DEBUG_OUT << "^" << name << ":\t";
if (hit.has_valid_attribute())
BOOST_SPIRIT_DEBUG_OUT << hit.value();
else
BOOST_SPIRIT_DEBUG_OUT << "undefined attribute";
BOOST_SPIRIT_DEBUG_OUT << "\n";
}
return hit;
}
#endif // BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_CLOSURES
}
///////////////////////////////////////////////////////////////////////////////
//
// Implementation note: The parser_context_linker, parser_scanner_linker and
// closure_context_linker classes are wrapped by a PP constant to allow
// redefinition of this classes outside of Spirit
//
///////////////////////////////////////////////////////////////////////////////
#if !defined(BOOST_SPIRIT_PARSER_CONTEXT_LINKER_DEFINED)
#define BOOST_SPIRIT_PARSER_CONTEXT_LINKER_DEFINED
///////////////////////////////////////////////////////////////////////////
//
// parser_context_linker is a debug wrapper for the ContextT template
// parameter of the rule<>, subrule<> and the grammar<> classes
//
///////////////////////////////////////////////////////////////////////////
template<typename ContextT>
struct parser_context_linker : public ContextT
{
typedef ContextT base_t;
template <typename ParserT>
parser_context_linker(ParserT const& p)
: ContextT(p) {}
template <typename ParserT, typename ScannerT>
void pre_parse(ParserT const& p, ScannerT &scan)
{
this->base_t::pre_parse(p, scan);
#if BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES
if (trace_parser(p.derived())) {
impl::print_node_info(
false,
scan.get_level(),
false,
parser_name(p.derived()),
scan.first,
scan.last);
}
scan.get_level()++;
#endif // BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES
}
template <typename ResultT, typename ParserT, typename ScannerT>
ResultT& post_parse(ResultT& hit, ParserT const& p, ScannerT &scan)
{
#if BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES
--scan.get_level();
if (trace_parser(p.derived())) {
impl::print_node_info(
hit,
scan.get_level(),
true,
parser_name(p.derived()),
scan.first,
scan.last);
}
#endif // BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES
return this->base_t::post_parse(hit, p, scan);
}
};
#endif // !defined(BOOST_SPIRIT_PARSER_CONTEXT_LINKER_DEFINED)
#if !defined(BOOST_SPIRIT_PARSER_SCANNER_LINKER_DEFINED)
#define BOOST_SPIRIT_PARSER_SCANNER_LINKER_DEFINED
///////////////////////////////////////////////////////////////////////////////
// This class is to avoid linker problems and to ensure a real singleton
// 'level' variable
struct debug_support
{
int& get_level()
{
static int level = 0;
return level;
}
};
template<typename ScannerT>
struct parser_scanner_linker : public ScannerT
{
parser_scanner_linker(ScannerT const &scan_) : ScannerT(scan_)
{}
int &get_level()
{ return debug.get_level(); }
private: debug_support debug;
};
#endif // !defined(BOOST_SPIRIT_PARSER_SCANNER_LINKER_DEFINED)
#if !defined(BOOST_SPIRIT_CLOSURE_CONTEXT_LINKER_DEFINED)
#define BOOST_SPIRIT_CLOSURE_CONTEXT_LINKER_DEFINED
///////////////////////////////////////////////////////////////////////////
//
// closure_context_linker is a debug wrapper for the closure template
// parameter of the rule<>, subrule<> and grammar classes
//
///////////////////////////////////////////////////////////////////////////
template<typename ContextT>
struct closure_context_linker : public parser_context_linker<ContextT>
{
typedef parser_context_linker<ContextT> base_t;
template <typename ParserT>
closure_context_linker(ParserT const& p)
: parser_context_linker<ContextT>(p) {}
template <typename ParserT, typename ScannerT>
void pre_parse(ParserT const& p, ScannerT &scan)
{ this->base_t::pre_parse(p, scan); }
template <typename ResultT, typename ParserT, typename ScannerT>
ResultT&
post_parse(ResultT& hit, ParserT const& p, ScannerT &scan)
{
#if BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_CLOSURES
if (hit && trace_parser(p.derived())) {
// for now, print out the return value only
return impl::print_closure_info(
this->base_t::post_parse(hit, p, scan),
scan.get_level(),
parser_name(p.derived())
);
}
#endif // BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_CLOSURES
return this->base_t::post_parse(hit, p, scan);
}
};
#endif // !defined(BOOST_SPIRIT_CLOSURE_CONTEXT_LINKER_DEFINED)
BOOST_SPIRIT_CLASSIC_NAMESPACE_END
}} // namespace BOOST_SPIRIT_CLASSIC_NS
#endif // defined(BOOST_SPIRIT_DEBUG)
#endif // !defined(BOOST_SPIRIT_DEBUG_NODE_HPP)
+555
View File
@@ -0,0 +1,555 @@
/*=============================================================================
Copyright (c) 2001-2003 Joel de Guzman
Copyright (c) 2002-2003 Hartmut Kaiser
http://spirit.sourceforge.net/
Use, modification and distribution is subject to the Boost Software
License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
=============================================================================*/
#if !defined(BOOST_SPIRIT_PARSER_NAMES_IPP)
#define BOOST_SPIRIT_PARSER_NAMES_IPP
#if defined(BOOST_SPIRIT_DEBUG)
#include <string>
#include <iostream>
#include <map>
#include <boost/config.hpp>
#ifdef BOOST_NO_STRINGSTREAM
#include <strstream>
#define BOOST_SPIRIT_SSTREAM std::strstream
std::string BOOST_SPIRIT_GETSTRING(std::strstream& ss)
{
ss << ends;
std::string rval = ss.str();
ss.freeze(false);
return rval;
}
#else
#include <sstream>
#define BOOST_SPIRIT_GETSTRING(ss) ss.str()
#define BOOST_SPIRIT_SSTREAM std::stringstream
#endif
namespace boost { namespace spirit {
BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN
///////////////////////////////////////////////////////////////////////////////
// from actions.hpp
template <typename ParserT, typename ActionT>
inline std::string
parser_name(action<ParserT, ActionT> const& p)
{
return std::string("action")
+ std::string("[")
+ parser_name(p.subject())
+ std::string("]");
}
///////////////////////////////////////////////////////////////////////////////
// from directives.hpp
template <typename ParserT>
inline std::string
parser_name(contiguous<ParserT> const& p)
{
return std::string("contiguous")
+ std::string("[")
+ parser_name(p.subject())
+ std::string("]");
}
template <typename ParserT>
inline std::string
parser_name(inhibit_case<ParserT> const& p)
{
return std::string("inhibit_case")
+ std::string("[")
+ parser_name(p.subject())
+ std::string("]");
}
template <typename A, typename B>
inline std::string
parser_name(longest_alternative<A, B> const& p)
{
return std::string("longest_alternative")
+ std::string("[")
+ parser_name(p.left()) + std::string(", ") + parser_name(p.right())
+ std::string("]");
}
template <typename A, typename B>
inline std::string
parser_name(shortest_alternative<A, B> const& p)
{
return std::string("shortest_alternative")
+ std::string("[")
+ parser_name(p.left()) + std::string(", ") + parser_name(p.right())
+ std::string("]");
}
///////////////////////////////////////////////////////////////////////////////
// from numerics.hpp
template <typename T, int Radix, unsigned MinDigits, int MaxDigits>
inline std::string
parser_name(uint_parser<T, Radix, MinDigits, MaxDigits> const& /*p*/)
{
BOOST_SPIRIT_SSTREAM stream;
stream << Radix << ", " << MinDigits << ", " << MaxDigits;
return std::string("uint_parser<")
+ BOOST_SPIRIT_GETSTRING(stream)
+ std::string(">");
}
template <typename T, int Radix, unsigned MinDigits, int MaxDigits>
inline std::string
parser_name(int_parser<T, Radix, MinDigits, MaxDigits> const& /*p*/)
{
BOOST_SPIRIT_SSTREAM stream;
stream << Radix << ", " << MinDigits << ", " << MaxDigits;
return std::string("int_parser<")
+ BOOST_SPIRIT_GETSTRING(stream)
+ std::string(">");
}
template <typename T, typename RealPoliciesT>
inline std::string
parser_name(real_parser<T, RealPoliciesT> const& /*p*/)
{
return std::string("real_parser");
}
///////////////////////////////////////////////////////////////////////////////
// from operators.hpp
template <typename A, typename B>
inline std::string
parser_name(sequence<A, B> const& p)
{
return std::string("sequence")
+ std::string("[")
+ parser_name(p.left()) + std::string(", ") + parser_name(p.right())
+ std::string("]");
}
template <typename A, typename B>
inline std::string
parser_name(sequential_or<A, B> const& p)
{
return std::string("sequential_or")
+ std::string("[")
+ parser_name(p.left()) + std::string(", ") + parser_name(p.right())
+ std::string("]");
}
template <typename A, typename B>
inline std::string
parser_name(alternative<A, B> const& p)
{
return std::string("alternative")
+ std::string("[")
+ parser_name(p.left()) + std::string(", ") + parser_name(p.right())
+ std::string("]");
}
template <typename A, typename B>
inline std::string
parser_name(intersection<A, B> const& p)
{
return std::string("intersection")
+ std::string("[")
+ parser_name(p.left()) + std::string(", ") + parser_name(p.right())
+ std::string("]");
}
template <typename A, typename B>
inline std::string
parser_name(difference<A, B> const& p)
{
return std::string("difference")
+ std::string("[")
+ parser_name(p.left()) + std::string(", ") + parser_name(p.right())
+ std::string("]");
}
template <typename A, typename B>
inline std::string
parser_name(exclusive_or<A, B> const& p)
{
return std::string("exclusive_or")
+ std::string("[")
+ parser_name(p.left()) + std::string(", ") + parser_name(p.right())
+ std::string("]");
}
template <typename S>
inline std::string
parser_name(optional<S> const& p)
{
return std::string("optional")
+ std::string("[")
+ parser_name(p.subject())
+ std::string("]");
}
template <typename S>
inline std::string
parser_name(kleene_star<S> const& p)
{
return std::string("kleene_star")
+ std::string("[")
+ parser_name(p.subject())
+ std::string("]");
}
template <typename S>
inline std::string
parser_name(positive<S> const& p)
{
return std::string("positive")
+ std::string("[")
+ parser_name(p.subject())
+ std::string("]");
}
///////////////////////////////////////////////////////////////////////////////
// from parser.hpp
template <typename DerivedT>
inline std::string
parser_name(parser<DerivedT> const& /*p*/)
{
return std::string("parser");
}
///////////////////////////////////////////////////////////////////////////////
// from primitives.hpp
template <typename DerivedT>
inline std::string
parser_name(char_parser<DerivedT> const &/*p*/)
{
return std::string("char_parser");
}
template <typename CharT>
inline std::string
parser_name(chlit<CharT> const &p)
{
return std::string("chlit(\'")
+ std::string(1, p.ch)
+ std::string("\')");
}
template <typename CharT>
inline std::string
parser_name(range<CharT> const &p)
{
return std::string("range(")
+ std::string(1, p.first) + std::string(", ") + std::string(1, p.last)
+ std::string(")");
}
template <typename IteratorT>
inline std::string
parser_name(chseq<IteratorT> const &p)
{
return std::string("chseq(\"")
+ std::string(p.first, p.last)
+ std::string("\")");
}
template <typename IteratorT>
inline std::string
parser_name(strlit<IteratorT> const &p)
{
return std::string("strlit(\"")
+ std::string(p.seq.first, p.seq.last)
+ std::string("\")");
}
inline std::string
parser_name(nothing_parser const&)
{
return std::string("nothing");
}
inline std::string
parser_name(epsilon_parser const&)
{
return std::string("epsilon");
}
inline std::string
parser_name(anychar_parser const&)
{
return std::string("anychar");
}
inline std::string
parser_name(alnum_parser const&)
{
return std::string("alnum");
}
inline std::string
parser_name(alpha_parser const&)
{
return std::string("alpha");
}
inline std::string
parser_name(cntrl_parser const&)
{
return std::string("cntrl");
}
inline std::string
parser_name(digit_parser const&)
{
return std::string("digit");
}
inline std::string
parser_name(graph_parser const&)
{
return std::string("graph");
}
inline std::string
parser_name(lower_parser const&)
{
return std::string("lower");
}
inline std::string
parser_name(print_parser const&)
{
return std::string("print");
}
inline std::string
parser_name(punct_parser const&)
{
return std::string("punct");
}
inline std::string
parser_name(blank_parser const&)
{
return std::string("blank");
}
inline std::string
parser_name(space_parser const&)
{
return std::string("space");
}
inline std::string
parser_name(upper_parser const&)
{
return std::string("upper");
}
inline std::string
parser_name(xdigit_parser const&)
{
return std::string("xdigit");
}
inline std::string
parser_name(eol_parser const&)
{
return std::string("eol");
}
inline std::string
parser_name(end_parser const&)
{
return std::string("end");
}
///////////////////////////////////////////////////////////////////////////////
// from rule.hpp
namespace impl {
struct node_registry
{
typedef std::pair<std::string, bool> rule_info;
typedef std::map<void const *, rule_info> rule_infos;
std::string find_node(void const *r)
{
rule_infos::const_iterator cit = infos.find(r);
if (cit != infos.end())
return (*cit).second.first;
return std::string("<unknown>");
}
bool trace_node(void const *r)
{
rule_infos::const_iterator cit = infos.find(r);
if (cit != infos.end())
return (*cit).second.second;
return BOOST_SPIRIT_DEBUG_TRACENODE;
}
bool register_node(void const *r, char const *name_to_register,
bool trace_node)
{
if (infos.find(r) != infos.end())
return false;
return infos.insert(rule_infos::value_type(r,
rule_info(std::string(name_to_register), trace_node))
).second;
}
bool unregister_node(void const *r)
{
if (infos.find(r) == infos.end())
return false;
return (1 == infos.erase(r));
}
private:
rule_infos infos;
};
inline node_registry &
get_node_registry()
{
static node_registry node_infos;
return node_infos;
}
} // namespace impl
template<
typename DerivedT, typename EmbedT,
typename T0, typename T1, typename T2
>
inline std::string
parser_name(impl::rule_base<DerivedT, EmbedT, T0, T1, T2> const& p)
{
return std::string("rule_base")
+ std::string("(")
+ impl::get_node_registry().find_node(&p)
+ std::string(")");
}
template<typename T0, typename T1, typename T2>
inline std::string
parser_name(rule<T0, T1, T2> const& p)
{
return std::string("rule")
+ std::string("(")
+ impl::get_node_registry().find_node(&p)
+ std::string(")");
}
///////////////////////////////////////////////////////////////////////////////
// from subrule.hpp
template <typename FirstT, typename RestT>
inline std::string
parser_name(subrule_list<FirstT, RestT> const &p)
{
return std::string("subrule_list")
+ std::string("(")
+ impl::get_node_registry().find_node(&p)
+ std::string(")");
}
template <int ID, typename DefT, typename ContextT>
inline std::string
parser_name(subrule_parser<ID, DefT, ContextT> const &p)
{
return std::string("subrule_parser")
+ std::string("(")
+ impl::get_node_registry().find_node(&p)
+ std::string(")");
}
template <int ID, typename ContextT>
inline std::string
parser_name(subrule<ID, ContextT> const &p)
{
BOOST_SPIRIT_SSTREAM stream;
stream << ID;
return std::string("subrule<")
+ BOOST_SPIRIT_GETSTRING(stream)
+ std::string(">(")
+ impl::get_node_registry().find_node(&p)
+ std::string(")");
}
///////////////////////////////////////////////////////////////////////////////
// from grammar.hpp
template <typename DerivedT, typename ContextT>
inline std::string
parser_name(grammar<DerivedT, ContextT> const& p)
{
return std::string("grammar")
+ std::string("(")
+ impl::get_node_registry().find_node(&p)
+ std::string(")");
}
///////////////////////////////////////////////////////////////////////////////
// decide, if a node is to be traced or not
template<
typename DerivedT, typename EmbedT,
typename T0, typename T1, typename T2
>
inline bool
trace_parser(impl::rule_base<DerivedT, EmbedT, T0, T1, T2>
const& p)
{
return impl::get_node_registry().trace_node(&p);
}
template<typename T0, typename T1, typename T2>
inline bool
trace_parser(rule<T0, T1, T2> const& p)
{
return impl::get_node_registry().trace_node(&p);
}
template <typename DerivedT, typename ContextT>
inline bool
trace_parser(grammar<DerivedT, ContextT> const& p)
{
return impl::get_node_registry().trace_node(&p);
}
template <typename DerivedT, int N, typename ContextT>
inline bool
trace_parser(impl::entry_grammar<DerivedT, N, ContextT> const& p)
{
return impl::get_node_registry().trace_node(&p);
}
template <int ID, typename ContextT>
bool
trace_parser(subrule<ID, ContextT> const& p)
{
return impl::get_node_registry().trace_node(&p);
}
template <typename ParserT, typename ActorTupleT>
bool
trace_parser(init_closure_parser<ParserT, ActorTupleT> const& p)
{
return impl::get_node_registry().trace_node(&p);
}
///////////////////////////////////////////////////////////////////////////////
BOOST_SPIRIT_CLASSIC_NAMESPACE_END
}} // namespace boost::spirit
#undef BOOST_SPIRIT_SSTREAM
#undef BOOST_SPIRIT_GETSTRING
#endif // defined(BOOST_SPIRIT_DEBUG)
#endif // !defined(BOOST_SPIRIT_PARSER_NAMES_IPP)
+81
View File
@@ -0,0 +1,81 @@
/*=============================================================================
Copyright (c) 2001-2003 Joel de Guzman
Copyright (c) 2002-2003 Hartmut Kaiser
http://spirit.sourceforge.net/
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
=============================================================================*/
#if !defined(BOOST_SPIRIT_MINIMAL_DEBUG_HPP)
#define BOOST_SPIRIT_MINIMAL_DEBUG_HPP
#if !defined(BOOST_SPIRIT_DEBUG_MAIN_HPP)
#error "You must include boost/spirit/debug.hpp, not boost/spirit/debug/minimal.hpp"
#endif
///////////////////////////////////////////////////////////////////////////////
//
// Minimum debugging tools support
//
///////////////////////////////////////////////////////////////////////////////
#if !defined(BOOST_SPIRIT_DEBUG_OUT)
#define BOOST_SPIRIT_DEBUG_OUT std::cout
#endif
///////////////////////////////////////////////////////////////////////////
//
// BOOST_SPIRIT_DEBUG_FLAGS controls the level of diagnostics printed
//
///////////////////////////////////////////////////////////////////////////
#if !defined(BOOST_SPIRIT_DEBUG_FLAGS_NONE)
#define BOOST_SPIRIT_DEBUG_FLAGS_NONE 0x0000 // no diagnostics at all
#endif
#if !defined(BOOST_SPIRIT_DEBUG_FLAGS_MAX)
#define BOOST_SPIRIT_DEBUG_FLAGS_MAX 0xFFFF // print maximal diagnostics
#endif
#if !defined(BOOST_SPIRIT_DEBUG_FLAGS)
#define BOOST_SPIRIT_DEBUG_FLAGS BOOST_SPIRIT_DEBUG_FLAGS_MAX
#endif
#if !defined(BOOST_SPIRIT_DEBUG_PRINT_SOME)
#define BOOST_SPIRIT_DEBUG_PRINT_SOME 20
#endif
#if !defined(BOOST_SPIRIT_DEBUG_RULE)
#define BOOST_SPIRIT_DEBUG_RULE(r)
#endif // !defined(BOOST_SPIRIT_DEBUG_RULE)
#if !defined(BOOST_SPIRIT_DEBUG_NODE)
#define BOOST_SPIRIT_DEBUG_NODE(r)
#endif // !defined(BOOST_SPIRIT_DEBUG_NODE)
#if !defined(BOOST_SPIRIT_DEBUG_GRAMMAR)
#define BOOST_SPIRIT_DEBUG_GRAMMAR(r)
#endif // !defined(BOOST_SPIRIT_DEBUG_GRAMMAR)
#if !defined(BOOST_SPIRIT_DEBUG_TRACE_RULE)
#define BOOST_SPIRIT_DEBUG_TRACE_RULE(r, t)
#endif // !defined(BOOST_SPIRIT_DEBUG_TRACE_RULE)
#if !defined(BOOST_SPIRIT_DEBUG_TRACE_NODE)
#define BOOST_SPIRIT_DEBUG_TRACE_NODE(r, t)
#endif // !defined(BOOST_SPIRIT_DEBUG_TRACE_NODE)
#if !defined(BOOST_SPIRIT_DEBUG_TRACE_GRAMMAR)
#define BOOST_SPIRIT_DEBUG_TRACE_GRAMMAR(r, t)
#endif // !defined(BOOST_SPIRIT_DEBUG_TRACE_GRAMMAR)
#if !defined(BOOST_SPIRIT_DEBUG_TRACE_RULE_NAME)
#define BOOST_SPIRIT_DEBUG_TRACE_RULE_NAME(r, n, t)
#endif // !defined(BOOST_SPIRIT_DEBUG_TRACE_RULE_NAME)
#if !defined(BOOST_SPIRIT_DEBUG_TRACE_NODE_NAME)
#define BOOST_SPIRIT_DEBUG_TRACE_NODE_NAME(r, n, t)
#endif // !defined(BOOST_SPIRIT_DEBUG_TRACE_NODE_NAME)
#if !defined(BOOST_SPIRIT_DEBUG_TRACE_GRAMMAR_NAME)
#define BOOST_SPIRIT_DEBUG_TRACE_GRAMMAR_NAME(r, n, t)
#endif // !defined(BOOST_SPIRIT_DEBUG_TRACE_GRAMMAR_NAME)
#endif // !defined(BOOST_SPIRIT_MINIMAL_DEBUG_HPP)
+254
View File
@@ -0,0 +1,254 @@
/*=============================================================================
Copyright (c) 2001-2003 Joel de Guzman
Copyright (c) 2002-2003 Hartmut Kaiser
http://spirit.sourceforge.net/
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
=============================================================================*/
#if !defined(BOOST_SPIRIT_PARSER_NAMES_HPP)
#define BOOST_SPIRIT_PARSER_NAMES_HPP
#if defined(BOOST_SPIRIT_DEBUG)
//////////////////////////////////
#include <boost/spirit/home/classic/namespace.hpp>
#include <boost/spirit/home/classic/core.hpp>
namespace boost { namespace spirit {
BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN
///////////////////////////////////////////////////////////////////////////////
//
// Declaration of helper functions, which return the name of a concrete
// parser instance. The functions are specialized on the parser types. The
// functions declared in this file are for the predefined parser types from
// the Spirit core library only, so additional functions might be provided as
// needed.
//
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// from actions.hpp
template <typename ParserT, typename ActionT>
std::string
parser_name(action<ParserT, ActionT> const& p);
///////////////////////////////////////////////////////////////////////////////
// from directives.hpp
template <typename ParserT>
std::string
parser_name(contiguous<ParserT> const& p);
template <typename ParserT>
std::string
parser_name(inhibit_case<ParserT> const& p);
template <typename A, typename B>
std::string
parser_name(longest_alternative<A, B> const& p);
template <typename A, typename B>
std::string
parser_name(shortest_alternative<A, B> const& p);
///////////////////////////////////////////////////////////////////////////////
// from grammar.hpp
template <typename DerivedT, typename ContextT>
std::string
parser_name(grammar<DerivedT, ContextT> const& p);
///////////////////////////////////////////////////////////////////////////////
// from numerics.hpp
template <typename T, int Radix, unsigned MinDigits, int MaxDigits>
std::string
parser_name(uint_parser<T, Radix, MinDigits, MaxDigits> const& p);
template <typename T, int Radix, unsigned MinDigits, int MaxDigits>
std::string
parser_name(int_parser<T, Radix, MinDigits, MaxDigits> const& p);
template <typename T, typename RealPoliciesT>
std::string
parser_name(real_parser<T, RealPoliciesT> const& p);
///////////////////////////////////////////////////////////////////////////////
// from operators.hpp
template <typename A, typename B>
std::string
parser_name(sequence<A, B> const& p);
template <typename A, typename B>
std::string
parser_name(sequential_or<A, B> const& p);
template <typename A, typename B>
std::string
parser_name(alternative<A, B> const& p);
template <typename A, typename B>
std::string
parser_name(intersection<A, B> const& p);
template <typename A, typename B>
std::string
parser_name(difference<A, B> const& p);
template <typename A, typename B>
std::string
parser_name(exclusive_or<A, B> const& p);
template <typename S>
std::string
parser_name(optional<S> const& p);
template <typename S>
std::string
parser_name(kleene_star<S> const& p);
template <typename S>
std::string
parser_name(positive<S> const& p);
///////////////////////////////////////////////////////////////////////////////
// from parser.hpp
template <typename DerivedT>
std::string
parser_name(parser<DerivedT> const& p);
///////////////////////////////////////////////////////////////////////////////
// from primitives.hpp
template <typename DerivedT>
std::string
parser_name(char_parser<DerivedT> const &p);
template <typename CharT>
std::string
parser_name(chlit<CharT> const &p);
template <typename CharT>
std::string
parser_name(range<CharT> const &p);
template <typename IteratorT>
std::string
parser_name(chseq<IteratorT> const &p);
template <typename IteratorT>
std::string
parser_name(strlit<IteratorT> const &p);
std::string
parser_name(nothing_parser const &p);
std::string
parser_name(epsilon_parser const &p);
std::string
parser_name(anychar_parser const &p);
std::string
parser_name(alnum_parser const &p);
std::string
parser_name(alpha_parser const &p);
std::string
parser_name(cntrl_parser const &p);
std::string
parser_name(digit_parser const &p);
std::string
parser_name(graph_parser const &p);
std::string
parser_name(lower_parser const &p);
std::string
parser_name(print_parser const &p);
std::string
parser_name(punct_parser const &p);
std::string
parser_name(blank_parser const &p);
std::string
parser_name(space_parser const &p);
std::string
parser_name(upper_parser const &p);
std::string
parser_name(xdigit_parser const &p);
std::string
parser_name(eol_parser const &p);
std::string
parser_name(end_parser const &p);
///////////////////////////////////////////////////////////////////////////////
// from rule.hpp
template<typename T0, typename T1, typename T2>
std::string
parser_name(rule<T0, T1, T2> const& p);
///////////////////////////////////////////////////////////////////////////////
// from subrule.hpp
template <typename FirstT, typename RestT>
std::string
parser_name(subrule_list<FirstT, RestT> const &p);
template <int ID, typename DefT, typename ContextT>
std::string
parser_name(subrule_parser<ID, DefT, ContextT> const &p);
template <int ID, typename ContextT>
std::string
parser_name(subrule<ID, ContextT> const &p);
///////////////////////////////////////////////////////////////////////////////
// from chset.hpp
///////////////////////////////////////////////////////////////////////////////
//
// Decide, if a node is to be traced or not
//
///////////////////////////////////////////////////////////////////////////////
template<
typename DerivedT, typename EmbedT,
typename T0, typename T1, typename T2
>
bool
trace_parser(impl::rule_base<DerivedT, EmbedT, T0, T1, T2>
const& p);
template <typename DerivedT, typename ContextT>
bool
trace_parser(grammar<DerivedT, ContextT> const& p);
template <int ID, typename ContextT>
bool
trace_parser(subrule<ID, ContextT> const& p);
template <typename ParserT, typename ActorTupleT>
struct init_closure_parser;
template <typename ParserT, typename ActorTupleT>
bool
trace_parser(init_closure_parser<ParserT, ActorTupleT> const& p);
///////////////////////////////////////////////////////////////////////////////
BOOST_SPIRIT_CLASSIC_NAMESPACE_END
}} // namespace BOOST_SPIRIT_CLASSIC_NS
//////////////////////////////////
#include <boost/spirit/home/classic/debug/impl/parser_names.ipp>
#endif // defined(BOOST_SPIRIT_DEBUG)
#endif // !defined(BOOST_SPIRIT_PARSER_NAMES_HPP)
+37
View File
@@ -0,0 +1,37 @@
/*=============================================================================
Copyright (c) 2006 Tobias Schwinger
http://spirit.sourceforge.net/
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
=============================================================================*/
#if !defined(BOOST_SPIRIT_DEBUG_TYPEOF_HPP)
#define BOOST_SPIRIT_DEBUG_TYPEOF_HPP
#include <boost/typeof/typeof.hpp>
#include <boost/spirit/home/classic/namespace.hpp>
#include <boost/spirit/home/classic/core/typeof.hpp>
namespace boost { namespace spirit {
BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN
// debug_node.hpp
template<typename ContextT> struct parser_context_linker;
template<typename ScannerT> struct scanner_context_linker;
template<typename ContextT> struct closure_context_linker;
BOOST_SPIRIT_CLASSIC_NAMESPACE_END
}} // namespace BOOST_SPIRIT_CLASSIC_NS
#include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP()
// debug_node.hpp
BOOST_TYPEOF_REGISTER_TEMPLATE(BOOST_SPIRIT_CLASSIC_NS::parser_context_linker,1)
BOOST_TYPEOF_REGISTER_TEMPLATE(BOOST_SPIRIT_CLASSIC_NS::scanner_context_linker,1)
BOOST_TYPEOF_REGISTER_TEMPLATE(BOOST_SPIRIT_CLASSIC_NS::closure_context_linker,1)
#endif