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

Last change on this file since 3770 was 3770, checked in by matszpk, 3 years ago

CLRadeonExtender: AsmExpr?: Calculate address (value) while comparing values (in section diffs mode).

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