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

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

CLRadeonExtender: Asm: Print only one 'Error: For comparisons two values must have this same relatives!' while evaluating
expression with section diffs.

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