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

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

CLRadeonExtender: AsmExpr?: Prefer checking relatives while comparing by using old method.

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