source: CLRX/CLRadeonExtender/trunk/amdasm/AsmExpression.cpp @ 3768

Last change on this file since 3768 was 3768, checked in by matszpk, 2 years ago

CLRadeonExtender: Asm: Add handling relspaces while comparing two values (compare operators).

File size: 73.1 KB
Line 
1/*
2 *  CLRadeonExtender - Unofficial OpenCL Radeon Extensions Library
3 *  Copyright (C) 2014-2018 Mateusz Szpakowski
4 *
5 *  This library is free software; you can redistribute it and/or
6 *  modify it under the terms of the GNU Lesser General Public
7 *  License as published by the Free Software Foundation; either
8 *  version 2.1 of the License, or (at your option) any later version.
9 *
10 *  This library is distributed in the hope that it will be useful,
11 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 *  Lesser General Public License for more details.
14 *
15 *  You should have received a copy of the GNU Lesser General Public
16 *  License along with this library; if not, write to the Free Software
17 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18 */
19
20#include <CLRX/Config.h>
21#include <string>
22#include <vector>
23#include <stack>
24#include <algorithm>
25#include <unordered_set>
26#include <unordered_map>
27#include <CLRX/utils/Utilities.h>
28#include <CLRX/amdasm/Assembler.h>
29#include "AsmInternals.h"
30
31using namespace CLRX;
32
33/*
34 * expressions
35 */
36
37// bitmask: if bit is enabled then operator can give message (error or warning)
38static const uint64_t operatorWithMessage = 
39        (1ULL<<int(AsmExprOp::DIVISION)) | (1ULL<<int(AsmExprOp::SIGNED_DIVISION)) |
40        (1ULL<<int(AsmExprOp::MODULO)) | (1ULL<<int(AsmExprOp::SIGNED_MODULO)) |
41        (1ULL<<int(AsmExprOp::SHIFT_LEFT)) | (1ULL<<int(AsmExprOp::SHIFT_RIGHT)) |
42        (1ULL<<int(AsmExprOp::SIGNED_SHIFT_RIGHT));
43
44AsmExpression::AsmExpression() : symOccursNum(0), relativeSymOccurs(false),
45            baseExpr(false)
46{ }
47
48// set symbol occurrences, operators and arguments, line positions for messages
49void AsmExpression::setParams(size_t _symOccursNum,
50          bool _relativeSymOccurs, size_t _opsNum, const AsmExprOp* _ops, size_t _opPosNum,
51          const LineCol* _opPos, size_t _argsNum, const AsmExprArg* _args, bool _baseExpr)
52{
53    symOccursNum = _symOccursNum;
54    relativeSymOccurs = _relativeSymOccurs;
55    baseExpr = _baseExpr;
56    args.reset(new AsmExprArg[_argsNum]);
57    ops.assign(_ops, _ops+_opsNum);
58    messagePositions.reset(new LineCol[_opPosNum]);
59    std::copy(_args, _args+_argsNum, args.get());
60    std::copy(_opPos, _opPos+_opPosNum, messagePositions.get());
61}
62
63AsmExpression::AsmExpression(const AsmSourcePos& _pos, size_t _symOccursNum,
64          bool _relSymOccurs, size_t _opsNum, const AsmExprOp* _ops, size_t _opPosNum,
65          const LineCol* _opPos, size_t _argsNum, const AsmExprArg* _args,
66          bool _baseExpr)
67        : sourcePos(_pos), symOccursNum(_symOccursNum), relativeSymOccurs(_relSymOccurs),
68          baseExpr(_baseExpr), ops(_ops, _ops+_opsNum)
69{
70    args.reset(new AsmExprArg[_argsNum]);
71    messagePositions.reset(new LineCol[_opPosNum]);
72    std::copy(_args, _args+_argsNum, args.get());
73    std::copy(_opPos, _opPos+_opPosNum, messagePositions.get());
74}
75
76AsmExpression::AsmExpression(const AsmSourcePos& _pos, size_t _symOccursNum,
77            bool _relSymOccurs, size_t _opsNum, size_t _opPosNum, size_t _argsNum,
78            bool _baseExpr)
79        : sourcePos(_pos), symOccursNum(_symOccursNum), relativeSymOccurs(_relSymOccurs),
80          baseExpr(_baseExpr), ops(_opsNum)
81{
82    args.reset(new AsmExprArg[_argsNum]);
83    messagePositions.reset(new LineCol[_opPosNum]);
84}
85
86AsmExpression::~AsmExpression()
87{
88    if (!baseExpr)
89    {
90        // delete all occurrences in expression at that place
91        for (size_t i = 0, j = 0; i < ops.size(); i++)
92            if (ops[i] == AsmExprOp::ARG_SYMBOL)
93            {
94                args[j].symbol->second.removeOccurrenceInExpr(this, j, i);
95                j++;
96            }
97            else if (ops[i]==AsmExprOp::ARG_VALUE)
98                j++;
99    }
100}
101
102// helper for handling errors
103
104#define ASMX_FAILED_BY_ERROR(PLACE, STRING) \
105    { \
106        assembler.printError(PLACE, STRING); \
107        failed = true; \
108    }
109
110#define ASMX_NOTGOOD_BY_ERROR(PLACE, STRING) \
111    { \
112        assembler.printError(PLACE, STRING); \
113        good = false; \
114    }
115
116// expression with relative symbols
117struct RelMultiply
118{
119    // multiplication of section
120    uint64_t multiply;
121    cxuint sectionId;
122};
123
124static inline bool compareRelMSectionLess(const RelMultiply& r1, const RelMultiply& r2)
125{ return r1.sectionId < r2.sectionId; }
126
127static void reduceRelMultiplies(std::vector<RelMultiply>& relmuls)
128{
129    size_t i = 0, j = 0;
130    uint64_t multiply = 0;
131    cxuint prevSect = ASMSECT_ABS;
132    for (i = 0; i < relmuls.size(); i++)
133    {
134        if (relmuls[i].sectionId != prevSect)
135        {
136            if (i != 0)
137                relmuls[j++] = { multiply, prevSect };
138            multiply = relmuls[i].multiply;
139            prevSect = relmuls[i].sectionId;
140        }
141        else
142            multiply += relmuls[i].multiply;
143    }
144    if (i != 0)
145        relmuls[j++] = { multiply, prevSect };
146    relmuls.resize(j);
147}
148
149static bool checkRelativesEquality(Assembler& assembler,
150            std::vector<RelMultiply>& relatives,
151            const Array<RelMultiply>& relatives2, bool checkRelSpaces)
152{
153    std::vector<RelMultiply> relSpaces1(relatives.size());
154    std::vector<RelMultiply> relSpaces2(relatives2.size());
155    const std::vector<AsmSection>& sections = assembler.getSections();
156   
157    bool haveRealRelSpaces = false;
158    if (checkRelSpaces)
159    {
160        // convert sections to relspaces
161        for (size_t i = 0; i < relSpaces1.size(); i++)
162            if (sections[relatives[i].sectionId].relSpace != UINT_MAX)
163            {
164                relSpaces1[i] = { relatives[i].multiply, 
165                        sections[relatives[i].sectionId].relSpace };
166                haveRealRelSpaces = true;
167            }
168            else // treat as separate relSpace
169                relSpaces1[i] = { relatives[i].multiply,
170                        0x80000000 | relatives[i].sectionId };
171       
172        for (size_t i = 0; i < relSpaces2.size(); i++)
173            if (sections[relatives2[i].sectionId].relSpace != UINT_MAX)
174            {
175                relSpaces2[i] = { relatives2[i].multiply, 
176                        sections[relatives2[i].sectionId].relSpace };
177                haveRealRelSpaces = true;
178            }
179            else // treat as separate relSpace
180                relSpaces2[i] = { relatives2[i].multiply,
181                        0x80000000 | relatives2[i].sectionId };
182    }
183   
184    if (!checkRelSpaces || !haveRealRelSpaces)
185    {
186        // if no check relspaces or if no real rel spaces in relatives
187        size_t requals = 0;
188        if (relatives2.size() != relatives.size())
189            return false;
190        else
191        {
192            // check whether relatives as same in two operands
193            for (const RelMultiply& r: relatives2)
194                for (RelMultiply& r2: relatives)
195                    if (r.multiply == r2.multiply &&
196                            r.sectionId == r2.sectionId)
197                    {
198                        r2.sectionId = ASMSECT_ABS; // ignore in next iter
199                        requals++;
200                        break;
201                    }
202            if (requals != relatives.size())
203                return false;
204        }
205    }
206    else
207    {
208        // sort
209        std::sort(relSpaces1.begin(), relSpaces1.end(), compareRelMSectionLess);
210        std::sort(relSpaces2.begin(), relSpaces2.end(), compareRelMSectionLess);
211        // reduce relspaces by sum multiplies
212        reduceRelMultiplies(relSpaces1);
213        reduceRelMultiplies(relSpaces2);
214       
215        /// compare relspaces
216        if (relSpaces1.size() != relSpaces2.size())
217            return false;
218        for (size_t i = 0; i < relSpaces1.size(); i++)
219            if (relSpaces1[i].multiply != relSpaces2[i].multiply ||
220                relSpaces1[i].sectionId != relSpaces2[i].sectionId)
221                return false;
222    }
223    return true;
224}
225
226AsmTryStatus AsmExpression::tryEvaluate(Assembler& assembler, size_t opStart, size_t opEnd,
227                 uint64_t& outValue, cxuint& outSectionId, bool withSectionDiffs) const
228{
229    if (symOccursNum != 0)
230        throw AsmException("Expression can't be evaluated if "
231                    "symbols still are unresolved!");
232   
233    bool failed = false;
234    bool tryLater = false;
235    uint64_t value = 0; // by default is zero
236    cxuint sectionId = 0;
237    if (!relativeSymOccurs)
238    {
239        // all value is absolute
240        std::stack<uint64_t> stack;
241       
242        size_t argPos = 0;
243        size_t opPos = 0;
244        size_t messagePosIndex = 0;
245       
246        // move messagePosIndex and argument position to opStart position
247        for (opPos = 0; opPos < opStart; opPos++)
248        {
249            if (ops[opPos]==AsmExprOp::ARG_VALUE)
250                argPos++;
251            if ((operatorWithMessage & (1ULL<<cxuint(ops[opPos])))!=0)
252                messagePosIndex++;
253        }
254       
255        while (opPos < opEnd)
256        {
257            const AsmExprOp op = ops[opPos++];
258            if (op == AsmExprOp::ARG_VALUE)
259            {
260                // push argument to stack
261                stack.push(args[argPos++].value);
262                continue;
263            }
264            value = stack.top();
265            stack.pop();
266            if (isUnaryOp(op))
267            {
268                // unary operator (-,~,!)
269                switch (op)
270                {
271                    case AsmExprOp::NEGATE:
272                        value = -value;
273                        break;
274                    case AsmExprOp::BIT_NOT:
275                        value = ~value;
276                        break;
277                    case AsmExprOp::LOGICAL_NOT:
278                        value = !value;
279                        break;
280                    default:
281                        break;
282                }
283            }
284            else if (isBinaryOp(op))
285            {
286                // get first argument (second in stack)
287                uint64_t value2 = stack.top();
288                stack.pop();
289                switch (op)
290                {
291                    case AsmExprOp::ADDITION:
292                        value = value2 + value;
293                        break;
294                    case AsmExprOp::SUBTRACT:
295                        value = value2 - value;
296                        break;
297                    case AsmExprOp::MULTIPLY:
298                        value = value2 * value;
299                        break;
300                    case AsmExprOp::DIVISION:
301                        if (value != 0)
302                            value = value2 / value;
303                        else // error
304                        {
305                            ASMX_FAILED_BY_ERROR(getSourcePos(messagePosIndex),
306                                   "Division by zero")
307                            value = 0;
308                        }
309                        messagePosIndex++;
310                        break;
311                    case AsmExprOp::SIGNED_DIVISION:
312                        if (value != 0)
313                            value = int64_t(value2) / int64_t(value);
314                        else // error
315                        {
316                            ASMX_FAILED_BY_ERROR(getSourcePos(messagePosIndex),
317                                   "Division by zero")
318                            value = 0;
319                        }
320                        messagePosIndex++;
321                        break;
322                    case AsmExprOp::MODULO:
323                        if (value != 0)
324                            value = value2 % value;
325                        else // error
326                        {
327                            ASMX_FAILED_BY_ERROR(getSourcePos(messagePosIndex),
328                                   "Division by zero")
329                            value = 0;
330                        }
331                        messagePosIndex++;
332                        break;
333                    case AsmExprOp::SIGNED_MODULO:
334                        if (value != 0)
335                            value = int64_t(value2) % int64_t(value);
336                        else // error
337                        {
338                            ASMX_FAILED_BY_ERROR(getSourcePos(messagePosIndex),
339                                   "Division by zero")
340                            value = 0;
341                        }
342                        messagePosIndex++;
343                        break;
344                    case AsmExprOp::BIT_AND:
345                        value = value2 & value;
346                        break;
347                    case AsmExprOp::BIT_OR:
348                        value = value2 | value;
349                        break;
350                    case AsmExprOp::BIT_XOR:
351                        value = value2 ^ value;
352                        break;
353                    case AsmExprOp::BIT_ORNOT:
354                        value = value2 | ~value;
355                        break;
356                    case AsmExprOp::SHIFT_LEFT:
357                        if (value < 64)
358                            value = value2 << value;
359                        else
360                        {
361                            assembler.printWarning(getSourcePos(messagePosIndex),
362                                   "Shift count out of range (between 0 and 63)");
363                            value = 0;
364                        }
365                        messagePosIndex++;
366                        break;
367                    case AsmExprOp::SHIFT_RIGHT:
368                        if (value < 64)
369                            value = value2 >> value;
370                        else
371                        {
372                            assembler.printWarning(getSourcePos(messagePosIndex),
373                                   "Shift count out of range (between 0 and 63)");
374                            value = 0;
375                        }
376                        messagePosIndex++;
377                        break;
378                    case AsmExprOp::SIGNED_SHIFT_RIGHT:
379                        if (value < 64)
380                            value = int64_t(value2) >> value;
381                        else
382                        {
383                            assembler.printWarning(getSourcePos(messagePosIndex),
384                                   "Shift count out of range (between 0 and 63)");
385                            value = (value2>=(1ULL<<63)) ? UINT64_MAX : 0;
386                        }
387                        messagePosIndex++;
388                        break;
389                    case AsmExprOp::LOGICAL_AND:
390                        value = value2 && value;
391                        break;
392                    case AsmExprOp::LOGICAL_OR:
393                        value = value2 || value;
394                        break;
395                    case AsmExprOp::EQUAL:
396                        value = (value2 == value) ? UINT64_MAX : 0;
397                        break;
398                    case AsmExprOp::NOT_EQUAL:
399                        value = (value2 != value) ? UINT64_MAX : 0;
400                        break;
401                    case AsmExprOp::LESS:
402                        value = (int64_t(value2) < int64_t(value))? UINT64_MAX: 0;
403                        break;
404                    case AsmExprOp::LESS_EQ:
405                        value = (int64_t(value2) <= int64_t(value)) ? UINT64_MAX : 0;
406                        break;
407                    case AsmExprOp::GREATER:
408                        value = (int64_t(value2) > int64_t(value)) ? UINT64_MAX : 0;
409                        break;
410                    case AsmExprOp::GREATER_EQ:
411                        value = (int64_t(value2) >= int64_t(value)) ? UINT64_MAX : 0;
412                        break;
413                    case AsmExprOp::BELOW:
414                        value = (value2 < value)? UINT64_MAX: 0;
415                        break;
416                    case AsmExprOp::BELOW_EQ:
417                        value = (value2 <= value) ? UINT64_MAX : 0;
418                        break;
419                    case AsmExprOp::ABOVE:
420                        value = (value2 > value) ? UINT64_MAX : 0;
421                        break;
422                    case AsmExprOp::ABOVE_EQ:
423                        value = (value2 >= value) ? UINT64_MAX : 0;
424                        break;
425                    default:
426                        break;
427                }
428            }
429            else if (op == AsmExprOp::CHOICE)
430            {
431                // get second and first (second and third in stack)
432                const uint64_t value2 = stack.top();
433                stack.pop();
434                const uint64_t value3 = stack.top();
435                stack.pop();
436                value = value3 ? value2 : value;
437            }
438            stack.push(value);
439        }
440       
441        if (!stack.empty())
442            value = stack.top();
443        sectionId = ASMSECT_ABS;
444    }
445    else
446    {
447        const bool sectDiffsPrepared = (assembler.formatHandler != nullptr &&
448             assembler.formatHandler->isSectionDiffsResolvable());
449       
450        // structure that contains relatives info: offset value and mult. of sections
451        struct ValueAndMultiplies
452        {
453            uint64_t value;
454            Array<RelMultiply> relatives;
455           
456            ValueAndMultiplies(uint64_t _value = 0) : value(_value)
457            { }
458            ValueAndMultiplies(uint64_t _value, cxuint _sectionId) : value(_value),
459                relatives({{1,_sectionId}})
460            { }
461        };
462       
463        std::stack<ValueAndMultiplies> stack;
464        size_t argPos = 0;
465        size_t opPos = 0;
466        size_t messagePosIndex = 0;
467        std::vector<RelMultiply> relatives;
468       
469        // move messagePosIndex and argument position to opStart position
470        for (opPos = 0; opPos < opStart; opPos++)
471        {
472            if (ops[opPos]==AsmExprOp::ARG_VALUE)
473                argPos++;
474            if ((operatorWithMessage & (1ULL<<cxuint(ops[opPos])))!=0)
475                messagePosIndex++;
476        }
477       
478        const std::vector<Array<cxuint> >& relSpacesSects = assembler.relSpacesSections;
479        const std::vector<AsmSection>& sections = assembler.sections;
480       
481        while (opPos < opEnd)
482        {
483            const AsmExprOp op = ops[opPos++];
484            if (op == AsmExprOp::ARG_VALUE)
485            {
486                if (args[argPos].relValue.sectionId != ASMSECT_ABS)
487                {
488                    uint64_t ovalue = args[argPos].relValue.value;
489                    cxuint osectId = args[argPos].relValue.sectionId;
490                    if (sectDiffsPrepared && sections[osectId].relSpace!=UINT_MAX)
491                    {
492                        // resolve section in relspace
493                        cxuint rsectId = relSpacesSects[sections[osectId].relSpace][0];
494                        ovalue += sections[osectId].relAddress -
495                                sections[rsectId].relAddress;
496                        osectId = rsectId;
497                    }
498                    stack.push(ValueAndMultiplies(ovalue, osectId));
499                }
500                else
501                    stack.push(args[argPos].value);
502                argPos++;
503                continue;
504            }
505            value = stack.top().value;
506            relatives.assign(stack.top().relatives.begin(), stack.top().relatives.end());
507            stack.pop();
508           
509            // handle unary operators
510            if (isUnaryOp(op))
511            {
512                switch (op)
513                {
514                    case AsmExprOp::NEGATE:
515                        for (RelMultiply& r: relatives)
516                            r.multiply = -r.multiply;
517                        value = -value;
518                        break;
519                    case AsmExprOp::BIT_NOT:
520                        for (RelMultiply& r: relatives)
521                            r.multiply = -r.multiply;
522                        value = ~value;
523                        break;
524                    case AsmExprOp::LOGICAL_NOT:
525                        if (!relatives.empty())
526                            ASMX_FAILED_BY_ERROR(sourcePos,
527                                 "Logical negation is not allowed to relative values")
528                        value = !value;
529                        break;
530                    default:
531                        break;
532                }
533            }
534            else if (isBinaryOp(op))
535            {
536                uint64_t value2 = stack.top().value;
537                const Array<RelMultiply> relatives2 = stack.top().relatives;
538                stack.pop();
539                switch (op)
540                {
541                    case AsmExprOp::ADDITION:
542                    case AsmExprOp::SUBTRACT:
543                    {
544                        if (op == AsmExprOp::SUBTRACT)
545                        {
546                            for (RelMultiply& r: relatives)
547                                r.multiply = -r.multiply; // negate before subtraction
548                            value = -value;
549                        }
550                        for (const RelMultiply& r2: relatives2)
551                        {
552                            bool rfound = false;
553                            for (RelMultiply& r: relatives)
554                                if (r.sectionId == r2.sectionId)
555                                {
556                                    r.multiply += r2.multiply;
557                                    rfound = true;
558                                }
559                           if (!rfound)
560                               relatives.push_back(r2);
561                        }
562                        // remove zeroes from relatives
563                        relatives.resize(std::remove_if(relatives.begin(), relatives.end(),
564                           [](const RelMultiply& r) { return r.multiply==0; }) -
565                           relatives.begin());
566                        value = value2 + value;
567                        break;
568                    }
569                    case AsmExprOp::MULTIPLY:
570                        // we do not multiply with relatives in two operands
571                        if (!relatives.empty() && !relatives2.empty())
572                            ASMX_FAILED_BY_ERROR(sourcePos,
573                                 "Multiplication is not allowed for two relative values")
574                        if (relatives2.empty())
575                        {
576                            // multiply relatives
577                            if (value2 != 0)
578                                for (RelMultiply& r: relatives)
579                                    r.multiply *= value2;
580                            else
581                                relatives.clear();
582                        }
583                        else
584                        {
585                            // multiply relatives2
586                            if (value != 0)
587                            {
588                                relatives.assign(relatives2.begin(), relatives2.end());
589                                for (RelMultiply& r: relatives)
590                                    r.multiply *= value;
591                            }
592                        }
593                        value = value2 * value;
594                        break;
595                    case AsmExprOp::DIVISION:
596                        if (!relatives.empty() || !relatives2.empty())
597                            ASMX_FAILED_BY_ERROR(sourcePos,
598                                 "Division is not allowed for any relative value")
599                        if (value != 0)
600                            value = value2 / value;
601                        else
602                        {
603                            // error
604                            ASMX_FAILED_BY_ERROR(getSourcePos(messagePosIndex),
605                                   "Division by zero")
606                            value = 0;
607                        }
608                        messagePosIndex++;
609                        break;
610                    case AsmExprOp::SIGNED_DIVISION:
611                        if (!relatives.empty()|| !relatives2.empty())
612                            ASMX_FAILED_BY_ERROR(sourcePos,
613                                 "Signed division is not allowed for any relative value")
614                        if (value != 0)
615                            value = int64_t(value2) / int64_t(value);
616                        else
617                        {
618                            // error
619                            ASMX_FAILED_BY_ERROR(getSourcePos(messagePosIndex),
620                                   "Division by zero")
621                            value = 0;
622                        }
623                        messagePosIndex++;
624                        break;
625                    case AsmExprOp::MODULO:
626                        if (!relatives.empty() || !relatives2.empty())
627                            ASMX_FAILED_BY_ERROR(sourcePos,
628                                 "Modulo is not allowed for any relative value")
629                        if (value != 0)
630                            value = value2 % value;
631                        else
632                        {
633                            // error
634                            ASMX_FAILED_BY_ERROR(getSourcePos(messagePosIndex),
635                                   "Division by zero")
636                            value = 0;
637                        }
638                        messagePosIndex++;
639                        break;
640                    case AsmExprOp::SIGNED_MODULO:
641                        if (!relatives.empty() || !relatives2.empty())
642                            ASMX_FAILED_BY_ERROR(sourcePos,
643                                 "Signed Modulo is not allowed for any relative value")
644                        if (value != 0)
645                            value = int64_t(value2) % int64_t(value);
646                        else
647                        {
648                            // error
649                            ASMX_FAILED_BY_ERROR(getSourcePos(messagePosIndex),
650                                   "Division by zero")
651                            value = 0;
652                        }
653                        messagePosIndex++;
654                        break;
655                    case AsmExprOp::BIT_AND:
656                        if (!relatives.empty() || !relatives2.empty())
657                            ASMX_FAILED_BY_ERROR(sourcePos,
658                                 "Binary AND is not allowed for any relative value")
659                        value = value2 & value;
660                        break;
661                    case AsmExprOp::BIT_OR:
662                        if (!relatives.empty() || !relatives2.empty())
663                            ASMX_FAILED_BY_ERROR(sourcePos,
664                                 "Binary OR is not allowed for any relative value")
665                        value = value2 | value;
666                        break;
667                    case AsmExprOp::BIT_XOR:
668                        if (!relatives.empty() || !relatives2.empty())
669                            ASMX_FAILED_BY_ERROR(sourcePos,
670                                 "Binary XOR is not allowed for any relative value")
671                        value = value2 ^ value;
672                        break;
673                    case AsmExprOp::BIT_ORNOT:
674                        if (!relatives.empty() || !relatives2.empty())
675                            ASMX_FAILED_BY_ERROR(sourcePos,
676                                 "Binary ORNOT is not allowed for any relative value")
677                        value = value2 | ~value;
678                        break;
679                    case AsmExprOp::SHIFT_LEFT:
680                        if (!relatives.empty())
681                            ASMX_FAILED_BY_ERROR(sourcePos, "Shift left is not allowed "
682                                    "for any for relative second value")
683                        else if (value < 64)
684                        {
685                            relatives.assign(relatives2.begin(), relatives2.end());
686                            for (RelMultiply& r: relatives)
687                                r.multiply <<= value;
688                            value = value2 << value;
689                        }
690                        else
691                        {
692                            assembler.printWarning(getSourcePos(messagePosIndex),
693                                   "Shift count out of range (between 0 and 63)");
694                            value = 0;
695                        }
696                        messagePosIndex++;
697                        break;
698                    case AsmExprOp::SHIFT_RIGHT:
699                        if (!relatives.empty() || !relatives2.empty())
700                            ASMX_FAILED_BY_ERROR(sourcePos,
701                                 "Shift right is not allowed for any relative value")
702                        if (value < 64)
703                            value = value2 >> value;
704                        else
705                        {
706                            assembler.printWarning(getSourcePos(messagePosIndex),
707                                   "Shift count out of range (between 0 and 63)");
708                            value = 0;
709                        }
710                        messagePosIndex++;
711                        break;
712                    case AsmExprOp::SIGNED_SHIFT_RIGHT:
713                        if (!relatives.empty() || !relatives2.empty())
714                            ASMX_FAILED_BY_ERROR(sourcePos, "Signed shift right is not "
715                                    "allowed for any relative value")
716                        if (value < 64)
717                            value = int64_t(value2) >> value;
718                        else
719                        {
720                            assembler.printWarning(getSourcePos(messagePosIndex),
721                                   "Shift count out of range (between 0 and 63)");
722                            value = (value2>=(1ULL<<63)) ? UINT64_MAX : 0;
723                        }
724                        messagePosIndex++;
725                        break;
726                    case AsmExprOp::LOGICAL_AND:
727                        if (!relatives.empty() || !relatives2.empty())
728                            ASMX_FAILED_BY_ERROR(sourcePos,
729                                 "Logical AND is not allowed for any relative value")
730                        value = value2 && value;
731                        break;
732                    case AsmExprOp::LOGICAL_OR:
733                        if (!relatives.empty() || !relatives2.empty())
734                            ASMX_FAILED_BY_ERROR(sourcePos,
735                                 "Logical OR is not allowed for any relative value")
736                        value = value2 || value;
737                        break;
738                    case AsmExprOp::EQUAL:
739                    case AsmExprOp::NOT_EQUAL:
740                    case AsmExprOp::LESS:
741                    case AsmExprOp::LESS_EQ:
742                    case AsmExprOp::GREATER:
743                    case AsmExprOp::GREATER_EQ:
744                    case AsmExprOp::BELOW:
745                    case AsmExprOp::BELOW_EQ:
746                    case AsmExprOp::ABOVE:
747                    case AsmExprOp::ABOVE_EQ:
748                    {
749                        if (!checkRelativesEquality(assembler, relatives, relatives2,
750                                    withSectionDiffs && !sectDiffsPrepared))
751                            ASMX_FAILED_BY_ERROR(sourcePos, "For comparisons "
752                                        "two values must have this same relatives!")
753                       
754                        if (withSectionDiffs && !sectDiffsPrepared)
755                            tryLater = true; // must be evaluated later
756                        relatives.clear();
757                        switch(op)
758                        {
759                            case AsmExprOp::EQUAL:
760                                value = (value2 == value) ? UINT64_MAX : 0;
761                                break;
762                            case AsmExprOp::NOT_EQUAL:
763                                value = (value2 != value) ? UINT64_MAX : 0;
764                                break;
765                            case AsmExprOp::LESS:
766                                value = (int64_t(value2) < int64_t(value))? UINT64_MAX: 0;
767                                break;
768                            case AsmExprOp::LESS_EQ:
769                                value = (int64_t(value2) <= int64_t(value)) ?
770                                        UINT64_MAX : 0;
771                                break;
772                            case AsmExprOp::GREATER:
773                                value = (int64_t(value2) > int64_t(value)) ? UINT64_MAX : 0;
774                                break;
775                            case AsmExprOp::GREATER_EQ:
776                                value = (int64_t(value2) >= int64_t(value)) ?
777                                        UINT64_MAX : 0;
778                                break;
779                            case AsmExprOp::BELOW:
780                                value = (value2 < value)? UINT64_MAX: 0;
781                                break;
782                            case AsmExprOp::BELOW_EQ:
783                                value = (value2 <= value)? UINT64_MAX: 0;
784                                break;
785                            case AsmExprOp::ABOVE:
786                                value = (value2 > value)? UINT64_MAX: 0;
787                                break;
788                            case AsmExprOp::ABOVE_EQ:
789                                value = (value2 >= value)? UINT64_MAX: 0;
790                                break;
791                            default:
792                                break;
793                        }
794                        break;
795                    }
796                    default:
797                        break;
798                }
799            }
800            else if (op == AsmExprOp::CHOICE)
801            {
802                const uint64_t value2 = stack.top().value;
803                const Array<RelMultiply> relatives2 = stack.top().relatives;
804                stack.pop();
805                const uint64_t value3 = stack.top().value;
806                const Array<RelMultiply> relatives3 = stack.top().relatives;
807                stack.pop();
808                if (!relatives3.empty())
809                    ASMX_FAILED_BY_ERROR(sourcePos,
810                         "Choice is not allowed for first relative value")
811                if (value3)
812                    relatives.assign(relatives2.begin(), relatives2.end());
813                value = value3 ? value2 : value;
814            }
815           
816            ValueAndMultiplies relOut(value);
817            relOut.relatives.assign(relatives.begin(), relatives.end());
818            stack.push(relOut);
819        }
820       
821        if (!stack.empty())
822        {
823            value = stack.top().value;
824            relatives.assign(stack.top().relatives.begin(), stack.top().relatives.end());
825        }
826       
827        if (relatives.empty())
828            sectionId = ASMSECT_ABS;
829        else if (relatives.size() == 1 && relatives.front().multiply == 1)
830            sectionId = relatives.front().sectionId;
831        else
832        {
833            bool moreThanOneRelSpace = false;
834            cxuint relSpace = UINT_MAX;
835            if (withSectionDiffs && !sectDiffsPrepared)
836                // resolve whether is one relspace or not
837                for (const RelMultiply r: relatives)
838                {
839                    if (sections[r.sectionId].relSpace != UINT_MAX)
840                    {
841                        if (relSpace != UINT_MAX &&
842                            relSpace != sections[r.sectionId].relSpace)
843                        {
844                            moreThanOneRelSpace = true;
845                            break;
846                        }
847                        relSpace = sections[r.sectionId].relSpace;
848                    }
849                    else // treat section without relspace as separate relspace
850                    {
851                        moreThanOneRelSpace = true;
852                        break;
853                    }
854                }
855            else
856                moreThanOneRelSpace = true;
857           
858            if (moreThanOneRelSpace)
859                ASMX_FAILED_BY_ERROR(sourcePos,
860                        "Only one relative=1 (section) can be result of expression")
861            else // not sure, should be evaluated after section diffs resolving
862                tryLater = true;
863        }
864       
865        if (sectDiffsPrepared && sectionId != ASMSECT_ABS &&
866            sections[sectionId].relSpace != UINT_MAX)
867        {   // find proper section
868            const Array<cxuint>& rlSections  = relSpacesSects[
869                                sections[sectionId].relSpace];
870            auto it = std::lower_bound(rlSections.begin(), rlSections.end(), sectionId,
871                [&sections](cxuint a, cxuint b)
872                { return sections[a].relAddress < sections[b].relAddress; });
873            cxuint newSectionId =  (it != rlSections.end()) ? *it : rlSections.front();
874            value += sections[sectionId].relAddress - sections[newSectionId].relAddress;
875        }
876    }
877    if (tryLater)
878        return AsmTryStatus::TRY_LATER;
879    if (!failed)
880    {
881        // write results only if no errors
882        outSectionId = sectionId;
883        outValue = value;
884    }
885    return failed ? AsmTryStatus::FAILED : AsmTryStatus::SUCCESS;
886}
887
888static const cxbyte asmOpPrioritiesTbl[] =
889{
890    /* higher value, higher priority */
891    7, // ARG_VALUE
892    7, // ARG_SYMBOL
893    6, // NEGATE
894    6, // BIT_NOT
895    6, // LOGICAL_NOT
896    6, // PLUS
897    3, // ADDITION
898    3, // SUBTRACT
899    5, // MULTIPLY
900    5, // DIVISION
901    5, // SIGNED_DIVISION
902    5, // MODULO
903    5, // SIGNED_MODULO
904    4, // BIT_AND
905    4, // BIT_OR
906    4, // BIT_XOR
907    4, // BIT_ORNOT
908    5, // SHIFT_LEFT
909    5, // SHIFT_RIGHT
910    5, // SIGNED_SHIFT_RIGHT
911    1, // LOGICAL_AND
912    1, // LOGICAL_OR
913    2, // EQUAL
914    2, // NOT_EQUAL
915    2, // LESS
916    2, // LESS_EQ
917    2, // GREATER
918    2, // GREATER_EQ
919    2, // BELOW
920    2, // BELOW_EQ
921    2, // ABOVE
922    2, // ABOVE_EQ
923    0, // CHOICE
924    0 // CHOICE_END
925};
926
927// method used also by AsmExprParse test co create expression from string
928AsmExpression* AsmExpression::parse(Assembler& assembler, size_t& linePos,
929                bool makeBase, bool dontResolveSymbolsLater)
930{
931    const char* outend = assembler.line+linePos;
932    AsmExpression* expr = parse(assembler, outend, makeBase, dontResolveSymbolsLater);
933    linePos = outend-(assembler.line+linePos);
934    return expr;
935}   
936
937struct CLRX_INTERNAL SymbolSnapshotHash: std::hash<CString>
938{
939    size_t operator()(const AsmSymbolEntry* e1) const
940    { return static_cast<const std::hash<CString>&>(*this)(e1->first); }
941};
942
943struct CLRX_INTERNAL SymbolSnapshotEqual
944{
945    bool operator()(const AsmSymbolEntry* e1, const AsmSymbolEntry* e2) const
946    { return e1->first == e2->first; }
947};
948
949/// internal class of temporary symbol (snapshot of symbol) map
950class CLRX_INTERNAL CLRX::AsmExpression::TempSymbolSnapshotMap: 
951        public std::unordered_set<AsmSymbolEntry*, SymbolSnapshotHash, SymbolSnapshotEqual>
952{ };
953
954AsmExpression* AsmExpression::createForSnapshot(const AsmSourcePos* exprSourcePos) const
955{
956    std::unique_ptr<AsmExpression> expr(new AsmExpression);
957    size_t argsNum = 0;
958    size_t msgPosNum = 0;
959    for (AsmExprOp op: ops)
960        if (AsmExpression::isArg(op))
961            argsNum++;
962        else if (operatorWithMessage & (1ULL<<int(op)))
963            msgPosNum++;
964    expr->sourcePos = sourcePos;
965    expr->sourcePos.exprSourcePos = exprSourcePos;
966    expr->ops = ops;
967    expr->args.reset(new AsmExprArg[argsNum]);
968    std::copy(args.get(), args.get()+argsNum, expr->args.get());
969    expr->messagePositions.reset(new LineCol[msgPosNum]);
970    std::copy(messagePositions.get(), messagePositions.get()+msgPosNum,
971              expr->messagePositions.get());
972    return expr.release();
973}
974
975/* create symbol entry for temporary snapshot expression. this is copy of
976 * original symbol entry that can holds snapshot expression instead of normal expression */
977static inline AsmSymbolEntry* createSymbolEntryForSnapshot(const AsmSymbolEntry& symEntry,
978            const AsmSourcePos* exprSourcePos)
979{
980    std::unique_ptr<AsmExpression> expr(
981            symEntry.second.expression->createForSnapshot(exprSourcePos));
982   
983    std::unique_ptr<AsmSymbolEntry> newSymEntry(new AsmSymbolEntry{
984            symEntry.first, AsmSymbol(expr.get(), false, false)});
985   
986    expr->setTarget(AsmExprTarget::symbolTarget(newSymEntry.get()));
987    expr.release();
988    newSymEntry->second.base = true;
989    return newSymEntry.release();
990}
991
992// main routine to create symbol snapshot with snapshot expressions
993bool AsmExpression::makeSymbolSnapshot(Assembler& assembler,
994           TempSymbolSnapshotMap* snapshotMap, const AsmSymbolEntry& symEntry,
995           AsmSymbolEntry*& outSymEntry, const AsmSourcePos* topParentSourcePos)
996{
997    struct StackEntry
998    {
999        AsmSymbolEntry* entry;
1000        size_t opIndex;
1001        size_t argIndex;
1002       
1003        explicit StackEntry(AsmSymbolEntry* _entry)
1004            : entry(_entry), opIndex(0), argIndex(0)
1005        { }
1006       
1007        AsmSymbolEntry* releaseEntry()
1008        {
1009            AsmSymbolEntry* out = entry;
1010            entry = nullptr;
1011            return out;
1012        }
1013    };
1014    std::stack<StackEntry> stack;
1015   
1016    outSymEntry = nullptr;
1017    {
1018        std::unique_ptr<AsmSymbolEntry> newSymEntry(
1019                    createSymbolEntryForSnapshot(symEntry, topParentSourcePos));
1020        auto res = snapshotMap->insert(newSymEntry.get());
1021        if (!res.second)
1022        {
1023            // do nothing (symbol snapshot already made)
1024            outSymEntry = *res.first;
1025            outSymEntry->second.refCount++;
1026            return true;
1027        }
1028        stack.push(StackEntry(newSymEntry.release()));
1029    }
1030   
1031    bool good = true;
1032   
1033    while (!stack.empty())
1034    {
1035        StackEntry& se = stack.top();
1036        size_t opIndex = se.opIndex;
1037        size_t argIndex = se.argIndex;
1038        AsmExpression* expr = se.entry->second.expression;
1039        const size_t opsSize = expr->ops.size();
1040       
1041        AsmExprArg* args = expr->args.get();
1042        AsmExprOp* ops = expr->ops.data();
1043        if (opIndex < opsSize)
1044        {
1045            for (; opIndex < opsSize; opIndex++)
1046                if (ops[opIndex] == AsmExprOp::ARG_SYMBOL)
1047                {
1048                    // check this symbol
1049                    AsmSymbolEntry* nextSymEntry = args[argIndex].symbol;
1050                    if (nextSymEntry->second.base)
1051                    {
1052                        // new base expression (set by using .'eqv')
1053                        std::unique_ptr<AsmSymbolEntry> newSymEntry(
1054                                    createSymbolEntryForSnapshot(*nextSymEntry,
1055                                     &(expr->sourcePos)));
1056                        auto res = snapshotMap->insert(newSymEntry.get());
1057                        if (!res.second)
1058                        {
1059                            // replace this symEntry by symbol from tempSymbolMap
1060                            nextSymEntry = *res.first;
1061                            args[argIndex].symbol = nextSymEntry;
1062                            nextSymEntry->second.refCount++;
1063                        }
1064                        else
1065                        {
1066                            // new symEntry to stack
1067                            stack.push(StackEntry(newSymEntry.release()));
1068                            se.argIndex = argIndex;
1069                            se.opIndex = opIndex;
1070                            break;
1071                        }
1072                    }
1073                   
1074                    if (nextSymEntry->second.hasValue)
1075                    {
1076                        // put value to argument
1077                        if (nextSymEntry->second.regRange)
1078                            ASMX_NOTGOOD_BY_ERROR(expr->getSourcePos(),
1079                                                 "Expression have register symbol")
1080                        ops[opIndex] = AsmExprOp::ARG_VALUE;
1081                        args[argIndex].relValue.value = nextSymEntry->second.value;
1082                        if (!assembler.isAbsoluteSymbol(nextSymEntry->second))
1083                        {
1084                            expr->relativeSymOccurs = true;
1085                            args[argIndex].relValue.sectionId = 
1086                                nextSymEntry->second.sectionId;
1087                        }
1088                        else
1089                            args[argIndex].relValue.sectionId = ASMSECT_ABS;
1090                    }
1091                    else // if not defined
1092                    {
1093                        args[argIndex].symbol->second.addOccurrenceInExpr(
1094                                        expr, argIndex, opIndex);
1095                        expr->symOccursNum++;
1096                    }
1097                   
1098                    argIndex++;
1099                }
1100                else if (ops[opIndex]==AsmExprOp::ARG_VALUE)
1101                    argIndex++;
1102        }
1103        if (opIndex == opsSize)
1104        {
1105            // check if expression is evaluatable
1106            AsmSymbolEntry* thisSymEntry = se.releaseEntry();
1107            if (expr->symOccursNum == 0) // no symbols, we try to evaluate
1108            {
1109                // evaluate and remove obsolete expression
1110                if (!expr->evaluate(assembler, thisSymEntry->second.value,
1111                            thisSymEntry->second.sectionId))
1112                    good = false;
1113                thisSymEntry->second.hasValue = true;
1114                delete thisSymEntry->second.expression;
1115                thisSymEntry->second.expression = nullptr;
1116            }
1117            thisSymEntry->second.base = false;
1118            thisSymEntry->second.snapshot = true;
1119            stack.pop();
1120            if (!stack.empty())
1121            {
1122                // put to place in parent expression
1123                StackEntry& parentStackEntry = stack.top();
1124                AsmExpression* parentExpr = parentStackEntry.entry->second.expression;
1125                parentExpr->args[parentStackEntry.argIndex].symbol = thisSymEntry;
1126                parentExpr->ops[parentStackEntry.opIndex] = AsmExprOp::ARG_SYMBOL;
1127            }
1128            else
1129            {
1130                // last we return it
1131                outSymEntry = thisSymEntry;
1132                break;
1133            }
1134        }
1135    }
1136    return good;
1137}
1138
1139// routine that call main makeSymbolSnapshot with error handling
1140bool AsmExpression::makeSymbolSnapshot(Assembler& assembler,
1141           const AsmSymbolEntry& symEntry, AsmSymbolEntry*& outSymEntry,
1142           const AsmSourcePos* parentExprSourcePos)
1143{
1144    TempSymbolSnapshotMap symbolSnapshots;
1145    bool good = true;
1146    try
1147    {
1148        good = makeSymbolSnapshot(assembler, &symbolSnapshots, symEntry, outSymEntry,
1149                    parentExprSourcePos);
1150        if (good)
1151            for (AsmSymbolEntry* symEntry: symbolSnapshots)
1152                // delete evaluated symbol entries (except output symbol entry)
1153                if (outSymEntry != symEntry && symEntry->second.hasValue)
1154                {
1155                    delete symEntry->second.expression;
1156                    symEntry->second.expression = nullptr;
1157                    delete symEntry;
1158                }
1159                else
1160                    assembler.symbolSnapshots.insert(symEntry);
1161        else // if failed
1162            for (AsmSymbolEntry* symEntry: symbolSnapshots)
1163            {
1164                assembler.symbolSnapshots.erase(symEntry);
1165                delete symEntry->second.expression;
1166                symEntry->second.expression = nullptr;
1167                delete symEntry;
1168            }
1169    }
1170    catch(...)
1171    {
1172        for (AsmSymbolEntry* symEntry: symbolSnapshots)
1173        {
1174            assembler.symbolSnapshots.erase(symEntry);
1175            delete symEntry->second.expression;
1176            symEntry->second.expression = nullptr;
1177            delete symEntry;
1178        }
1179        throw;
1180    }   
1181    return good;
1182}
1183
1184AsmExpression* AsmExpression::createExprToEvaluate(Assembler& assembler) const
1185{
1186    TempSymbolSnapshotMap symbolSnapshots;
1187   
1188    try
1189    {
1190    size_t argsNum = 0;
1191    size_t msgPosNum = 0;
1192    for (AsmExprOp op: ops)
1193        if (AsmExpression::isArg(op))
1194            argsNum++;
1195    else if (operatorWithMessage & (1ULL<<int(op)))
1196        msgPosNum++;
1197    std::unique_ptr<AsmExpression> newExpr(new AsmExpression(
1198            sourcePos, symOccursNum, relativeSymOccurs, ops.size(), ops.data(),
1199            msgPosNum, messagePositions.get(), argsNum, args.get(), false));
1200    argsNum = 0;
1201    bool good = true;
1202    // try to resolve symbols
1203    for (AsmExprOp& op: newExpr->ops)
1204        if (AsmExpression::isArg(op))
1205        {
1206            if (op == AsmExprOp::ARG_SYMBOL) // if
1207            {
1208                AsmExprArg& arg = newExpr->args[argsNum];
1209                AsmSymbolEntry* symEntry = arg.symbol;
1210                if (symEntry!=nullptr && symEntry->second.base)
1211                    // create symbol snapshot if symbol is base
1212                    // only if for regular expression (not base
1213                    good &= newExpr->makeSymbolSnapshot(assembler, &symbolSnapshots,
1214                                *symEntry, symEntry, &sourcePos);
1215                if (symEntry==nullptr || !symEntry->second.hasValue)
1216                {
1217                    // no symbol not found
1218                    std::string errorMsg("Expression have unresolved symbol '");
1219                    errorMsg += symEntry->first.c_str();
1220                    errorMsg += '\'';
1221                    ASMX_NOTGOOD_BY_ERROR(sourcePos, errorMsg.c_str())
1222                }
1223                else
1224                {
1225                    if (symEntry->second.hasValue)
1226                    {
1227                        // resolve only if have symbol have value,
1228                        // but do not that if expression will be base for snapshot
1229                        if (!assembler.isAbsoluteSymbol(symEntry->second))
1230                        {
1231                            newExpr->relativeSymOccurs = true;
1232                            arg.relValue.sectionId = symEntry->second.sectionId;
1233                        }
1234                        arg.relValue.value = symEntry->second.value;
1235                        newExpr->symOccursNum--;
1236                        op = AsmExprOp::ARG_VALUE;
1237                    }
1238                }
1239            }
1240            argsNum++;
1241        }
1242   
1243    if (!good)
1244        return nullptr;
1245    // add expression into symbol occurrences in expressions
1246    for (AsmSymbolEntry* symEntry: symbolSnapshots)
1247    {
1248        if (!symEntry->second.hasValue)
1249            assembler.symbolSnapshots.insert(symEntry);
1250        else
1251        {
1252            // delete symbol snapshoft if have new value
1253            delete symEntry->second.expression;
1254            symEntry->second.expression = nullptr;
1255            delete symEntry;
1256        }
1257    }
1258    symbolSnapshots.clear();
1259    return newExpr.release();
1260    }
1261    catch(...)
1262    {
1263        // delete symbol snapshots if exception occurred
1264        for (AsmSymbolEntry* symEntry: symbolSnapshots)
1265        {
1266            // remove from assembler symbolSnapshots
1267            assembler.symbolSnapshots.erase(symEntry);
1268            // remove this snapshot
1269            delete symEntry->second.expression;
1270            symEntry->second.expression = nullptr;
1271            delete symEntry;
1272        }
1273        throw;
1274    }
1275}
1276
1277AsmExpression* AsmExpression::parse(Assembler& assembler, const char*& linePtr,
1278            bool makeBase, bool dontResolveSymbolsLater)
1279{
1280    struct ConExprOpEntry
1281    {
1282        AsmExprOp op;
1283        cxuint priority;
1284        size_t lineColPos;
1285    };
1286
1287    std::stack<ConExprOpEntry> stack;
1288    std::vector<AsmExprOp> ops;
1289    std::vector<AsmExprArg> args;
1290    std::vector<LineCol> messagePositions;
1291    std::vector<LineCol> outMsgPositions;
1292   
1293    TempSymbolSnapshotMap symbolSnapshots;
1294   
1295    try
1296    {
1297    const char* startString = linePtr;
1298    const char* end = assembler.line + assembler.lineSize;
1299    size_t parenthesisCount = 0;
1300    size_t symOccursNum = 0;
1301    bool good = true;
1302    bool relativeSymOccurs = false;
1303   
1304    // indicate what is expected at current place
1305    enum ExpectedToken
1306    {
1307        XT_FIRST = 0,   // operator or argument
1308        XT_OP = 1,  // expected operator
1309        XT_ARG = 2  // expected argument
1310    };
1311    ExpectedToken expectedToken = XT_FIRST;
1312    std::unique_ptr<AsmExpression> expr(new AsmExpression);
1313    expr->sourcePos = assembler.getSourcePos(startString);
1314   
1315    while (linePtr != end)
1316    {
1317        skipSpacesToEnd(linePtr, end);
1318        if (linePtr == end) break;
1319       
1320        LineCol lineCol = { 0, 0 };
1321        AsmExprOp op = AsmExprOp::NONE;
1322        bool expectedPrimaryExpr = false;
1323        //const size_t oldParenthesisCount = parenthesisCount;
1324        bool doExit = false;
1325       
1326        const char* beforeToken = linePtr;
1327        /* parse expression operator or value/symbol */
1328        switch(*linePtr)
1329        {
1330            case '(':
1331                if (expectedToken == XT_OP)
1332                    ASMX_NOTGOOD_BY_ERROR(linePtr, "Expected operator")
1333                else
1334                {
1335                    expectedToken = XT_FIRST;
1336                    parenthesisCount++;
1337                }
1338                linePtr++;
1339                break;
1340            case ')':
1341                if (expectedToken != XT_OP)
1342                    ASMX_NOTGOOD_BY_ERROR(linePtr, "Expected operator or value or symbol")
1343                else
1344                {
1345                    if (parenthesisCount==0)
1346                    { doExit = true; break; }
1347                    parenthesisCount--;
1348                }
1349                linePtr++;
1350                break;
1351            case '+':
1352                op = (expectedToken == XT_OP) ? AsmExprOp::ADDITION : AsmExprOp::PLUS;
1353                linePtr++;
1354                break;
1355            case '-':
1356                op = (expectedToken == XT_OP) ? AsmExprOp::SUBTRACT : AsmExprOp::NEGATE;
1357                linePtr++;
1358                break;
1359            case '*':
1360                op = AsmExprOp::MULTIPLY;
1361                linePtr++;
1362                break;
1363            case '/':
1364                lineCol = assembler.translatePos(linePtr);
1365                if (linePtr+1 != end && linePtr[1] == '/')
1366                {
1367                    op = AsmExprOp::DIVISION;
1368                    linePtr++;
1369                }
1370                else // standard GNU as signed division
1371                    op = AsmExprOp::SIGNED_DIVISION;
1372                linePtr++;
1373                break;
1374            case '%':
1375                lineCol = assembler.translatePos(linePtr);
1376                if (linePtr+1 != end && linePtr[1] == '%')
1377                {
1378                    op = AsmExprOp::MODULO;
1379                    linePtr++;
1380                }
1381                else // standard GNU as signed modulo
1382                    op = AsmExprOp::SIGNED_MODULO;
1383                linePtr++;
1384                break;
1385            case '&':
1386                if (linePtr+1 != end && linePtr[1] == '&')
1387                {
1388                    op = AsmExprOp::LOGICAL_AND;
1389                    linePtr++;
1390                }
1391                else // standard bitwise AND
1392                    op = AsmExprOp::BIT_AND;
1393                linePtr++;
1394                break;
1395            case '|':
1396                if (linePtr+1 != end && linePtr[1] == '|')
1397                {
1398                    op = AsmExprOp::LOGICAL_OR;
1399                    linePtr++;
1400                }
1401                else // standard bitwise OR
1402                    op = AsmExprOp::BIT_OR;
1403                linePtr++;
1404                break;
1405            case '!':
1406                if (expectedToken == XT_OP) // ORNOT or logical not
1407                {
1408                    if (linePtr+1 != end && linePtr[1] == '=')
1409                    {
1410                        // we have != (inequality operator)
1411                        op = AsmExprOp::NOT_EQUAL;
1412                        linePtr++;
1413                    }
1414                    else
1415                        op = AsmExprOp::BIT_ORNOT;
1416                }
1417                else
1418                    op = AsmExprOp::LOGICAL_NOT;
1419                linePtr++;
1420                break;
1421            case '~':
1422                if (expectedToken != XT_OP)
1423                    op = AsmExprOp::BIT_NOT;
1424                else
1425                    ASMX_NOTGOOD_BY_ERROR(linePtr,
1426                        "Expected non-unary operator, '(', or end of expression")
1427                linePtr++;
1428                break;
1429            case '^':
1430                op = AsmExprOp::BIT_XOR;
1431                linePtr++;
1432                break;
1433            case '<':
1434                if (linePtr+1 != end && linePtr[1] == '<')
1435                {
1436                    lineCol = assembler.translatePos(linePtr);
1437                    op = AsmExprOp::SHIFT_LEFT;
1438                    linePtr++;
1439                }
1440                else if (linePtr+1 != end && linePtr[1] == '>')
1441                {
1442                    op = AsmExprOp::NOT_EQUAL;
1443                    linePtr++;
1444                }
1445                else if (linePtr+1 != end && linePtr[1] == '=')
1446                {
1447                    // less or equal than (signed and unsigned)
1448                    if (linePtr+2 != end && linePtr[2] == '@')
1449                    {
1450                        op = AsmExprOp::BELOW_EQ;
1451                        linePtr++;
1452                    }
1453                    else
1454                        op = AsmExprOp::LESS_EQ;
1455                    linePtr++;
1456                }
1457                // less than (signed and unsigned)
1458                else if (linePtr+1 != end && linePtr[1] == '@')
1459                {
1460                    op = AsmExprOp::BELOW;
1461                    linePtr++;
1462                }
1463                else
1464                    op = AsmExprOp::LESS;
1465                linePtr++;
1466                break;
1467            case '>':
1468                if (linePtr+1 != end && linePtr[1] == '>')
1469                {
1470                    lineCol = assembler.translatePos(linePtr);
1471                    if (linePtr+2 != end && linePtr[2] == '>')
1472                    {
1473                        op = AsmExprOp::SIGNED_SHIFT_RIGHT;
1474                        linePtr++;
1475                    }
1476                    else
1477                        op = AsmExprOp::SHIFT_RIGHT;
1478                    linePtr++;
1479                }
1480                else if (linePtr+1 != end && linePtr[1] == '=')
1481                {
1482                    // greater or equal than (signed and unsigned)
1483                    if (linePtr+2 != end && linePtr[2] == '@')
1484                    {
1485                        op = AsmExprOp::ABOVE_EQ;
1486                        linePtr++;
1487                    }
1488                    else
1489                        op = AsmExprOp::GREATER_EQ;
1490                    linePtr++;
1491                }
1492                // greater than (signed and unsigned)
1493                else if (linePtr+1 != end && linePtr[1] == '@')
1494                {
1495                    op = AsmExprOp::ABOVE;
1496                    linePtr++;
1497                }
1498                else
1499                    op = AsmExprOp::GREATER;
1500                linePtr++;
1501                break;
1502            case '=':
1503                if (linePtr+1 != end && linePtr[1] == '=')
1504                {
1505                    op = AsmExprOp::EQUAL;
1506                    linePtr++;
1507                }
1508                else
1509                    expectedPrimaryExpr = true;
1510                linePtr++;
1511                break;
1512            case '?':
1513                lineCol = assembler.translatePos(linePtr);
1514                op = AsmExprOp::CHOICE_START;
1515                linePtr++;
1516                break;
1517            case ':':
1518                if (linePtr+1==end || linePtr[1]!=':')
1519                {
1520                    op = AsmExprOp::CHOICE;
1521                    linePtr++;
1522                    break;
1523                }
1524                // otherwise try parse symbol
1525            default: // parse symbol or value
1526                if (expectedToken != XT_OP)
1527                {
1528                    ExpectedToken oldExpectedToken = expectedToken;
1529                    expectedToken = XT_OP;
1530                    AsmSymbolEntry* symEntry;
1531                   
1532                    const char* symEndStr = linePtr;
1533                    Assembler::ParseState parseState = assembler.parseSymbol(symEndStr,
1534                                     symEntry, true, dontResolveSymbolsLater);
1535                    if (symEntry!=nullptr && symEntry->second.regRange)
1536                    {
1537                        ASMX_NOTGOOD_BY_ERROR(linePtr, "Expression have register symbol")
1538                        continue;
1539                    }
1540                   
1541                    if (parseState == Assembler::ParseState::FAILED) good = false;
1542                    AsmExprArg arg;
1543                    arg.relValue.sectionId = ASMSECT_ABS;
1544                    if (parseState != Assembler::ParseState::MISSING)
1545                    {
1546                        if (symEntry!=nullptr && symEntry->second.base && !makeBase)
1547                            // create symbol snapshot if symbol is base
1548                            // only if for regular expression (not base
1549                            good &= makeSymbolSnapshot(assembler, &symbolSnapshots,
1550                                      *symEntry, symEntry, &(expr->sourcePos));
1551                        if (symEntry==nullptr ||
1552                            (!symEntry->second.hasValue && dontResolveSymbolsLater))
1553                        {
1554                            // no symbol not found
1555                            std::string errorMsg("Expression have unresolved symbol '");
1556                            errorMsg.append(linePtr, symEndStr);
1557                            errorMsg += '\'';
1558                            ASMX_NOTGOOD_BY_ERROR(linePtr, errorMsg.c_str())
1559                        }
1560                        else
1561                        {
1562                            if (symEntry->second.hasValue && !makeBase)
1563                            {
1564                                // resolve only if have symbol have value,
1565                                // but do not that if expression will be base for snapshot
1566                                if (!assembler.isAbsoluteSymbol(symEntry->second))
1567                                {
1568                                    relativeSymOccurs = true;
1569                                    arg.relValue.sectionId = symEntry->second.sectionId;
1570                                }
1571                                arg.relValue.value = symEntry->second.value;
1572                                args.push_back(arg);
1573                                ops.push_back(AsmExprOp::ARG_VALUE);
1574                            }
1575                            else
1576                            {
1577                                /* add symbol */
1578                                symOccursNum++;
1579                                arg.symbol = symEntry;
1580                                args.push_back(arg);
1581                                ops.push_back(AsmExprOp::ARG_SYMBOL);
1582                            }
1583                        }
1584                        linePtr = symEndStr;
1585                    }
1586                    else if (parenthesisCount != 0 || (*linePtr >= '0' &&
1587                            *linePtr <= '9') || *linePtr == '\'')
1588                    {
1589                        // other we try to parse number
1590                        const char* oldStr = linePtr;
1591                        if (!assembler.parseLiteral(arg.value, linePtr))
1592                        {
1593                            arg.value = 0;
1594                            if (linePtr != end && oldStr == linePtr)
1595                                // skip one character when end is in this same place
1596                                // (avoids infinity loops)
1597                                linePtr++;
1598                            good = false;
1599                        }
1600                        args.push_back(arg);
1601                        ops.push_back(AsmExprOp::ARG_VALUE);
1602                    }
1603                    else
1604                    {
1605                        // otherwise we finish parsing
1606                        expectedToken = oldExpectedToken;
1607                        doExit = true; break;
1608                    }
1609                }
1610                else
1611                {
1612                    // otherwise we exit if no left parenthesis
1613                    if (parenthesisCount == 0)
1614                    { doExit = true; break; }
1615                    else
1616                    {
1617                        linePtr++;
1618                        ASMX_NOTGOOD_BY_ERROR(linePtr, "Garbages at end of expression")
1619                    }
1620                }
1621        }
1622       
1623        if (op != AsmExprOp::NONE && !isUnaryOp(op) && expectedToken != XT_OP)
1624        {
1625            expectedPrimaryExpr = true;
1626            op = AsmExprOp::NONE;
1627        }
1628        // when no argument before binary/ternary operator
1629        if (expectedPrimaryExpr)
1630        {
1631            ASMX_NOTGOOD_BY_ERROR(beforeToken,
1632                     "Expected primary expression before operator")
1633            continue;
1634        }
1635       
1636        // determine what is next expected
1637        if (op != AsmExprOp::NONE && !isUnaryOp(op))
1638            expectedToken = (expectedToken == XT_OP) ? XT_ARG : XT_OP;
1639       
1640        //afterParenthesis = (oldParenthesisCount < parenthesisCount);
1641        const size_t lineColPos = (lineCol.lineNo!=0) ? messagePositions.size() : SIZE_MAX;
1642        if (lineCol.lineNo!=0)
1643            messagePositions.push_back(lineCol);
1644       
1645        if (op != AsmExprOp::NONE)
1646        {
1647            // if operator
1648            const bool unaryOp = isUnaryOp(op);
1649            const cxuint priority = (parenthesisCount<<3) +
1650                        asmOpPrioritiesTbl[cxuint(op)];
1651           
1652            if (op == AsmExprOp::CHOICE)
1653            {
1654                /* second part of choice */
1655                while (!stack.empty())
1656                {
1657                    const ConExprOpEntry& entry = stack.top();
1658                    if (priority > entry.priority || (priority == entry.priority &&
1659                        entry.op == AsmExprOp::CHOICE_START))
1660                        break;
1661                    if (entry.op != AsmExprOp::PLUS)
1662                        ops.push_back(entry.op);
1663                    if (entry.lineColPos != SIZE_MAX && entry.op != AsmExprOp::CHOICE_START)
1664                        outMsgPositions.push_back(messagePositions[entry.lineColPos]);
1665                    stack.pop();
1666                }
1667                if (stack.empty())
1668                {
1669                    linePtr--; // go back to ':'
1670                    expectedToken = XT_OP;
1671                    doExit = true;
1672                    break;
1673                }
1674                else if (stack.top().op != AsmExprOp::CHOICE_START ||
1675                        stack.top().priority != priority)
1676                {
1677                    // not found
1678                    ASMX_NOTGOOD_BY_ERROR(beforeToken, "Missing '?' before ':'")
1679                    continue; // do noy change stack and them entries
1680                }
1681                ConExprOpEntry& entry = stack.top();
1682                entry.op = AsmExprOp::CHOICE;
1683                entry.lineColPos = SIZE_MAX;
1684            }
1685            else
1686            {
1687                while (!stack.empty())
1688                {
1689                    const ConExprOpEntry& entry = stack.top();
1690                    if (priority +
1691                        /* because ?: is computed from right to left we adds 1 to priority
1692                         * to force put new node higher than left node */
1693                        (op == AsmExprOp::CHOICE_START) + unaryOp > entry.priority)
1694                        break;
1695                    if (entry.op == AsmExprOp::CHOICE_START)
1696                    {
1697                        // unfinished choice
1698                        stack.pop();
1699                        ASMX_NOTGOOD_BY_ERROR(messagePositions[entry.lineColPos],
1700                                 "Missing ':' for '?'")
1701                        break;
1702                    }
1703                    if (entry.op != AsmExprOp::PLUS)
1704                        ops.push_back(entry.op);
1705                    if (entry.lineColPos != SIZE_MAX && entry.op != AsmExprOp::CHOICE_START)
1706                        outMsgPositions.push_back(messagePositions[entry.lineColPos]);
1707                    stack.pop();
1708                }
1709                stack.push({ op, priority, lineColPos });
1710            }
1711        }
1712       
1713        if (doExit) // exit from parsing
1714            break;
1715    }
1716    if (parenthesisCount != 0) // print error
1717        ASMX_NOTGOOD_BY_ERROR(linePtr, "Missing ')'")
1718    if (expectedToken != XT_OP)
1719    {
1720        if (!ops.empty() || !stack.empty())
1721            ASMX_NOTGOOD_BY_ERROR(linePtr, "Unterminated expression")
1722    }
1723    else
1724    {
1725        while (!stack.empty())
1726        {
1727            const ConExprOpEntry& entry = stack.top();
1728            if (entry.op == AsmExprOp::CHOICE_START)
1729            {
1730                // unfinished choice
1731                ASMX_NOTGOOD_BY_ERROR(messagePositions[entry.lineColPos],
1732                         "Missing ':' for '?'")
1733                break;
1734            }
1735            if (entry.op != AsmExprOp::PLUS)
1736                ops.push_back(entry.op);
1737            if (entry.lineColPos != SIZE_MAX && entry.op != AsmExprOp::CHOICE_START)
1738                outMsgPositions.push_back(messagePositions[entry.lineColPos]);
1739            stack.pop();
1740        }
1741    }
1742   
1743    if (good)
1744    {
1745        const size_t argsNum = args.size();
1746        // if good, we set symbol occurrences, operators, arguments ...
1747        expr->setParams(symOccursNum, relativeSymOccurs,
1748                  ops.size(), ops.data(), outMsgPositions.size(), outMsgPositions.data(),
1749                  argsNum, args.data(), makeBase);
1750        if (!makeBase)
1751        {
1752            // add expression into symbol occurrences in expressions
1753            // only for non-base expressions
1754            for (size_t i = 0, j = 0; j < argsNum; i++)
1755                if (ops[i] == AsmExprOp::ARG_SYMBOL)
1756                {
1757                    args[j].symbol->second.addOccurrenceInExpr(expr.get(), j, i);
1758                    j++;
1759                }
1760                else if (ops[i]==AsmExprOp::ARG_VALUE)
1761                    j++;
1762        }
1763        for (AsmSymbolEntry* symEntry: symbolSnapshots)
1764        {
1765            if (!symEntry->second.hasValue)
1766                assembler.symbolSnapshots.insert(symEntry);
1767            else
1768            {
1769                // delete symbol snapshoft if have new value
1770                delete symEntry->second.expression;
1771                symEntry->second.expression = nullptr;
1772                delete symEntry;
1773            }
1774        }
1775        symbolSnapshots.clear();
1776        return expr.release();
1777    }
1778    else
1779    {
1780        // delete symbol snapshots if error
1781        for (AsmSymbolEntry* symEntry: symbolSnapshots)
1782        {
1783            delete symEntry->second.expression;
1784            symEntry->second.expression = nullptr;
1785            delete symEntry;
1786        }
1787        return nullptr;
1788    }
1789    }
1790    catch(...)
1791    {
1792        // delete symbol snapshots if exception occurred
1793        for (AsmSymbolEntry* symEntry: symbolSnapshots)
1794        {
1795            // remove from assembler symbolSnapshots
1796            assembler.symbolSnapshots.erase(symEntry);
1797            // remove this snapshot
1798            delete symEntry->second.expression;
1799            symEntry->second.expression = nullptr;
1800            delete symEntry;
1801        }
1802        throw;
1803    }
1804}
1805
1806// go to top in expression from specified operator index (can be used to divide expression)
1807size_t AsmExpression::toTop(size_t opIndex) const
1808{
1809    std::stack<cxbyte> stack;
1810    while (true)
1811    {
1812        AsmExprOp op = ops[opIndex];
1813        if (op==AsmExprOp::ARG_VALUE)
1814        {
1815            while (!stack.empty() && --stack.top()==0)
1816                stack.pop();
1817            if (stack.empty())
1818                break; // is end
1819        }
1820        else // operators
1821            stack.push(isUnaryOp(op) ? 1 : (isBinaryOp(op) ? 2 : 3));
1822        opIndex--;
1823    }
1824    return opIndex;
1825}
1826
1827static const uint32_t acceptedCharsAfterFastExpr =
1828    (1U<<('!'-32)) | (1U<<('%'-32)) | (1U<<('&'-32)) | (1U<<('*'-32)) | (1U<<('!'-32)) |
1829        (1U<<('+'-32)) | (1U<<('-'-32)) | (1U<<('/'-32)) | (1U<<('<'-32)) |
1830        (1U<<('='-32)) | (1U<<('>'-32)) | (1U<<('?'-32));
1831
1832bool AsmExpression::fastExprEvaluate(Assembler& assembler, const char*& linePtr,
1833                        uint64_t& value)
1834{
1835    const char* end = assembler.line + assembler.lineSize;
1836    uint64_t sum = 0;
1837    bool addition = true;
1838    const char* tmpLinePtr = linePtr;
1839    skipSpacesToEnd(tmpLinePtr, end);
1840   
1841    // main loop
1842    while (true)
1843    {
1844        // loop for chain of unary '+' and '-'
1845        while (tmpLinePtr != end && (*tmpLinePtr=='+' || *tmpLinePtr=='-'))
1846        {
1847            if (*tmpLinePtr=='-')
1848                addition = !addition;
1849            skipCharAndSpacesToEnd(tmpLinePtr, end);
1850        }
1851        uint64_t tmp = 0;
1852        if (tmpLinePtr == end || (!isDigit(*tmpLinePtr) && *tmpLinePtr!='\''))
1853            return false;
1854        if (!assembler.parseLiteralNoError(tmp, tmpLinePtr))
1855            return false;
1856        if (tmpLinePtr!=end && (*tmpLinePtr=='f' || *tmpLinePtr=='b'))
1857        {   // if local label
1858            const char* t = tmpLinePtr-1;
1859            while (t!=linePtr-1 && isDigit(*t)) t--;
1860            if (t==linePtr-1 || isSpace(*t)) // if local label
1861                return false;
1862        }
1863        // add or subtract
1864        sum += addition ? tmp : -tmp;
1865        // skip to next '+' or '-'
1866        skipSpacesToEnd(tmpLinePtr, end);
1867        if (tmpLinePtr==end || (*tmpLinePtr!='+' && *tmpLinePtr!='-'))
1868            break; // end
1869        // otherwise we continue
1870        addition = (*tmpLinePtr=='+');
1871        skipCharAndSpacesToEnd(tmpLinePtr, end);
1872    }
1873    if (tmpLinePtr==end ||
1874        // check whether is not other operator
1875        (*tmpLinePtr!='~' && *tmpLinePtr!='^' && *tmpLinePtr!='|' &&
1876        (*tmpLinePtr<32 || *tmpLinePtr>=64 ||
1877        // check whether is not other operator (by checking rest of characters)
1878        ((1U<<(*tmpLinePtr-32)) & acceptedCharsAfterFastExpr)==0)))
1879    {
1880        value = sum;
1881        linePtr = tmpLinePtr;
1882        return true;
1883    }
1884    return false;
1885}
1886
1887bool AsmExpression::fastExprEvaluate(Assembler& assembler, size_t& linePos,
1888                        uint64_t& value)
1889{
1890    const char* linePtr = assembler.line + linePos;
1891    bool res = fastExprEvaluate(assembler, linePtr, value);
1892    linePos = linePtr - assembler.line;
1893    return res;
1894}
Note: See TracBrowser for help on using the repository browser.