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

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

CLRadeonExtender: Asm: Working section diffs comparison on expressions.

File size: 73.9 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                       
760                        if (withSectionDiffs && !sectDiffsPrepared)
761                            tryLater = true; // must be evaluated later
762                        relatives.clear();
763                        value += fixAddr1;
764                        value2 += fixAddr2;
765                        switch(op)
766                        {
767                            case AsmExprOp::EQUAL:
768                                value = (value2 == value) ? UINT64_MAX : 0;
769                                break;
770                            case AsmExprOp::NOT_EQUAL:
771                                value = (value2 != value) ? UINT64_MAX : 0;
772                                break;
773                            case AsmExprOp::LESS:
774                                value = (int64_t(value2) < int64_t(value))? UINT64_MAX: 0;
775                                break;
776                            case AsmExprOp::LESS_EQ:
777                                value = (int64_t(value2) <= int64_t(value)) ?
778                                        UINT64_MAX : 0;
779                                break;
780                            case AsmExprOp::GREATER:
781                                value = (int64_t(value2) > int64_t(value)) ? UINT64_MAX : 0;
782                                break;
783                            case AsmExprOp::GREATER_EQ:
784                                value = (int64_t(value2) >= int64_t(value)) ?
785                                        UINT64_MAX : 0;
786                                break;
787                            case AsmExprOp::BELOW:
788                                value = (value2 < value)? UINT64_MAX: 0;
789                                break;
790                            case AsmExprOp::BELOW_EQ:
791                                value = (value2 <= value)? UINT64_MAX: 0;
792                                break;
793                            case AsmExprOp::ABOVE:
794                                value = (value2 > value)? UINT64_MAX: 0;
795                                break;
796                            case AsmExprOp::ABOVE_EQ:
797                                value = (value2 >= value)? UINT64_MAX: 0;
798                                break;
799                            default:
800                                break;
801                        }
802                        break;
803                    }
804                    default:
805                        break;
806                }
807            }
808            else if (op == AsmExprOp::CHOICE)
809            {
810                const uint64_t value2 = stack.top().value;
811                const Array<RelMultiply> relatives2 = stack.top().relatives;
812                stack.pop();
813                const uint64_t value3 = stack.top().value;
814                const Array<RelMultiply> relatives3 = stack.top().relatives;
815                stack.pop();
816                if (!relatives3.empty())
817                    ASMX_FAILED_BY_ERROR(sourcePos,
818                         "Choice is not allowed for first relative value")
819                if (value3)
820                    relatives.assign(relatives2.begin(), relatives2.end());
821                value = value3 ? value2 : value;
822            }
823           
824            ValueAndMultiplies relOut(value);
825            relOut.relatives.assign(relatives.begin(), relatives.end());
826            stack.push(relOut);
827        }
828       
829        if (!stack.empty())
830        {
831            value = stack.top().value;
832            relatives.assign(stack.top().relatives.begin(), stack.top().relatives.end());
833        }
834       
835        if (relatives.empty())
836            sectionId = ASMSECT_ABS;
837        else if (relatives.size() == 1 && relatives.front().multiply == 1)
838            sectionId = relatives.front().sectionId;
839        else
840        {
841            bool moreThanOneRelSpace = false;
842            cxuint relSpace = UINT_MAX;
843            if (withSectionDiffs && !sectDiffsPrepared)
844                // resolve whether is one relspace or not
845                for (const RelMultiply r: relatives)
846                {
847                    if (sections[r.sectionId].relSpace != UINT_MAX)
848                    {
849                        if (relSpace != UINT_MAX &&
850                            relSpace != sections[r.sectionId].relSpace)
851                        {
852                            moreThanOneRelSpace = true;
853                            break;
854                        }
855                        relSpace = sections[r.sectionId].relSpace;
856                    }
857                    else // treat section without relspace as separate relspace
858                    {
859                        moreThanOneRelSpace = true;
860                        break;
861                    }
862                }
863            else
864                moreThanOneRelSpace = true;
865           
866            if (moreThanOneRelSpace)
867                ASMX_FAILED_BY_ERROR(sourcePos,
868                        "Only one relative=1 (section) can be result of expression")
869            else // not sure, should be evaluated after section diffs resolving
870                tryLater = true;
871        }
872       
873        if (sectDiffsPrepared && sectionId != ASMSECT_ABS &&
874            sections[sectionId].relSpace != UINT_MAX)
875        {   // find proper section
876            const Array<cxuint>& rlSections  = relSpacesSects[
877                                sections[sectionId].relSpace];
878            uint64_t valAddr = sections[sectionId].relAddress + value;
879            auto it = std::lower_bound(rlSections.begin(), rlSections.end(), ASMSECT_ABS,
880                [&sections,valAddr](cxuint a, cxuint b)
881                {
882                    uint64_t relAddr1 = a!=ASMSECT_ABS ? sections[a].relAddress : valAddr;
883                    uint64_t relAddr2 = b!=ASMSECT_ABS ? sections[b].relAddress : valAddr;
884                    return relAddr1 < relAddr2;
885                });
886            // if section address higher than current address
887            if ((it == rlSections.end() || sections[*it].relAddress != valAddr) &&
888                    it != rlSections.begin())
889                --it;
890           
891            cxuint newSectionId = (it != rlSections.end()) ? *it : rlSections.back();
892            value += sections[sectionId].relAddress - sections[newSectionId].relAddress;
893            sectionId = newSectionId;
894        }
895    }
896    if (tryLater)
897        return AsmTryStatus::TRY_LATER;
898    if (!failed)
899    {
900        // write results only if no errors
901        outSectionId = sectionId;
902        outValue = value;
903    }
904    return failed ? AsmTryStatus::FAILED : AsmTryStatus::SUCCESS;
905}
906
907static const cxbyte asmOpPrioritiesTbl[] =
908{
909    /* higher value, higher priority */
910    7, // ARG_VALUE
911    7, // ARG_SYMBOL
912    6, // NEGATE
913    6, // BIT_NOT
914    6, // LOGICAL_NOT
915    6, // PLUS
916    3, // ADDITION
917    3, // SUBTRACT
918    5, // MULTIPLY
919    5, // DIVISION
920    5, // SIGNED_DIVISION
921    5, // MODULO
922    5, // SIGNED_MODULO
923    4, // BIT_AND
924    4, // BIT_OR
925    4, // BIT_XOR
926    4, // BIT_ORNOT
927    5, // SHIFT_LEFT
928    5, // SHIFT_RIGHT
929    5, // SIGNED_SHIFT_RIGHT
930    1, // LOGICAL_AND
931    1, // LOGICAL_OR
932    2, // EQUAL
933    2, // NOT_EQUAL
934    2, // LESS
935    2, // LESS_EQ
936    2, // GREATER
937    2, // GREATER_EQ
938    2, // BELOW
939    2, // BELOW_EQ
940    2, // ABOVE
941    2, // ABOVE_EQ
942    0, // CHOICE
943    0 // CHOICE_END
944};
945
946// method used also by AsmExprParse test co create expression from string
947AsmExpression* AsmExpression::parse(Assembler& assembler, size_t& linePos,
948                bool makeBase, bool dontResolveSymbolsLater)
949{
950    const char* outend = assembler.line+linePos;
951    AsmExpression* expr = parse(assembler, outend, makeBase, dontResolveSymbolsLater);
952    linePos = outend-(assembler.line+linePos);
953    return expr;
954}   
955
956struct CLRX_INTERNAL SymbolSnapshotHash: std::hash<CString>
957{
958    size_t operator()(const AsmSymbolEntry* e1) const
959    { return static_cast<const std::hash<CString>&>(*this)(e1->first); }
960};
961
962struct CLRX_INTERNAL SymbolSnapshotEqual
963{
964    bool operator()(const AsmSymbolEntry* e1, const AsmSymbolEntry* e2) const
965    { return e1->first == e2->first; }
966};
967
968/// internal class of temporary symbol (snapshot of symbol) map
969class CLRX_INTERNAL CLRX::AsmExpression::TempSymbolSnapshotMap: 
970        public std::unordered_set<AsmSymbolEntry*, SymbolSnapshotHash, SymbolSnapshotEqual>
971{ };
972
973AsmExpression* AsmExpression::createForSnapshot(const AsmSourcePos* exprSourcePos) const
974{
975    std::unique_ptr<AsmExpression> expr(new AsmExpression);
976    size_t argsNum = 0;
977    size_t msgPosNum = 0;
978    for (AsmExprOp op: ops)
979        if (AsmExpression::isArg(op))
980            argsNum++;
981        else if (operatorWithMessage & (1ULL<<int(op)))
982            msgPosNum++;
983    expr->sourcePos = sourcePos;
984    expr->sourcePos.exprSourcePos = exprSourcePos;
985    expr->ops = ops;
986    expr->args.reset(new AsmExprArg[argsNum]);
987    std::copy(args.get(), args.get()+argsNum, expr->args.get());
988    expr->messagePositions.reset(new LineCol[msgPosNum]);
989    std::copy(messagePositions.get(), messagePositions.get()+msgPosNum,
990              expr->messagePositions.get());
991    return expr.release();
992}
993
994/* create symbol entry for temporary snapshot expression. this is copy of
995 * original symbol entry that can holds snapshot expression instead of normal expression */
996static inline AsmSymbolEntry* createSymbolEntryForSnapshot(const AsmSymbolEntry& symEntry,
997            const AsmSourcePos* exprSourcePos)
998{
999    std::unique_ptr<AsmExpression> expr(
1000            symEntry.second.expression->createForSnapshot(exprSourcePos));
1001   
1002    std::unique_ptr<AsmSymbolEntry> newSymEntry(new AsmSymbolEntry{
1003            symEntry.first, AsmSymbol(expr.get(), false, false)});
1004   
1005    expr->setTarget(AsmExprTarget::symbolTarget(newSymEntry.get()));
1006    expr.release();
1007    newSymEntry->second.base = true;
1008    return newSymEntry.release();
1009}
1010
1011// main routine to create symbol snapshot with snapshot expressions
1012bool AsmExpression::makeSymbolSnapshot(Assembler& assembler,
1013           TempSymbolSnapshotMap* snapshotMap, const AsmSymbolEntry& symEntry,
1014           AsmSymbolEntry*& outSymEntry, const AsmSourcePos* topParentSourcePos)
1015{
1016    struct StackEntry
1017    {
1018        AsmSymbolEntry* entry;
1019        size_t opIndex;
1020        size_t argIndex;
1021       
1022        explicit StackEntry(AsmSymbolEntry* _entry)
1023            : entry(_entry), opIndex(0), argIndex(0)
1024        { }
1025       
1026        AsmSymbolEntry* releaseEntry()
1027        {
1028            AsmSymbolEntry* out = entry;
1029            entry = nullptr;
1030            return out;
1031        }
1032    };
1033    std::stack<StackEntry> stack;
1034   
1035    outSymEntry = nullptr;
1036    {
1037        std::unique_ptr<AsmSymbolEntry> newSymEntry(
1038                    createSymbolEntryForSnapshot(symEntry, topParentSourcePos));
1039        auto res = snapshotMap->insert(newSymEntry.get());
1040        if (!res.second)
1041        {
1042            // do nothing (symbol snapshot already made)
1043            outSymEntry = *res.first;
1044            outSymEntry->second.refCount++;
1045            return true;
1046        }
1047        stack.push(StackEntry(newSymEntry.release()));
1048    }
1049   
1050    bool good = true;
1051   
1052    while (!stack.empty())
1053    {
1054        StackEntry& se = stack.top();
1055        size_t opIndex = se.opIndex;
1056        size_t argIndex = se.argIndex;
1057        AsmExpression* expr = se.entry->second.expression;
1058        const size_t opsSize = expr->ops.size();
1059       
1060        AsmExprArg* args = expr->args.get();
1061        AsmExprOp* ops = expr->ops.data();
1062        if (opIndex < opsSize)
1063        {
1064            for (; opIndex < opsSize; opIndex++)
1065                if (ops[opIndex] == AsmExprOp::ARG_SYMBOL)
1066                {
1067                    // check this symbol
1068                    AsmSymbolEntry* nextSymEntry = args[argIndex].symbol;
1069                    if (nextSymEntry->second.base)
1070                    {
1071                        // new base expression (set by using .'eqv')
1072                        std::unique_ptr<AsmSymbolEntry> newSymEntry(
1073                                    createSymbolEntryForSnapshot(*nextSymEntry,
1074                                     &(expr->sourcePos)));
1075                        auto res = snapshotMap->insert(newSymEntry.get());
1076                        if (!res.second)
1077                        {
1078                            // replace this symEntry by symbol from tempSymbolMap
1079                            nextSymEntry = *res.first;
1080                            args[argIndex].symbol = nextSymEntry;
1081                            nextSymEntry->second.refCount++;
1082                        }
1083                        else
1084                        {
1085                            // new symEntry to stack
1086                            stack.push(StackEntry(newSymEntry.release()));
1087                            se.argIndex = argIndex;
1088                            se.opIndex = opIndex;
1089                            break;
1090                        }
1091                    }
1092                   
1093                    if (nextSymEntry->second.hasValue)
1094                    {
1095                        // put value to argument
1096                        if (nextSymEntry->second.regRange)
1097                            ASMX_NOTGOOD_BY_ERROR(expr->getSourcePos(),
1098                                                 "Expression have register symbol")
1099                        ops[opIndex] = AsmExprOp::ARG_VALUE;
1100                        args[argIndex].relValue.value = nextSymEntry->second.value;
1101                        if (!assembler.isAbsoluteSymbol(nextSymEntry->second))
1102                        {
1103                            expr->relativeSymOccurs = true;
1104                            args[argIndex].relValue.sectionId = 
1105                                nextSymEntry->second.sectionId;
1106                        }
1107                        else
1108                            args[argIndex].relValue.sectionId = ASMSECT_ABS;
1109                    }
1110                    else // if not defined
1111                    {
1112                        args[argIndex].symbol->second.addOccurrenceInExpr(
1113                                        expr, argIndex, opIndex);
1114                        expr->symOccursNum++;
1115                    }
1116                   
1117                    argIndex++;
1118                }
1119                else if (ops[opIndex]==AsmExprOp::ARG_VALUE)
1120                    argIndex++;
1121        }
1122        if (opIndex == opsSize)
1123        {
1124            // check if expression is evaluatable
1125            AsmSymbolEntry* thisSymEntry = se.releaseEntry();
1126            if (expr->symOccursNum == 0) // no symbols, we try to evaluate
1127            {
1128                // evaluate and remove obsolete expression
1129                if (!expr->evaluate(assembler, thisSymEntry->second.value,
1130                            thisSymEntry->second.sectionId))
1131                    good = false;
1132                thisSymEntry->second.hasValue = true;
1133                delete thisSymEntry->second.expression;
1134                thisSymEntry->second.expression = nullptr;
1135            }
1136            thisSymEntry->second.base = false;
1137            thisSymEntry->second.snapshot = true;
1138            stack.pop();
1139            if (!stack.empty())
1140            {
1141                // put to place in parent expression
1142                StackEntry& parentStackEntry = stack.top();
1143                AsmExpression* parentExpr = parentStackEntry.entry->second.expression;
1144                parentExpr->args[parentStackEntry.argIndex].symbol = thisSymEntry;
1145                parentExpr->ops[parentStackEntry.opIndex] = AsmExprOp::ARG_SYMBOL;
1146            }
1147            else
1148            {
1149                // last we return it
1150                outSymEntry = thisSymEntry;
1151                break;
1152            }
1153        }
1154    }
1155    return good;
1156}
1157
1158// routine that call main makeSymbolSnapshot with error handling
1159bool AsmExpression::makeSymbolSnapshot(Assembler& assembler,
1160           const AsmSymbolEntry& symEntry, AsmSymbolEntry*& outSymEntry,
1161           const AsmSourcePos* parentExprSourcePos)
1162{
1163    TempSymbolSnapshotMap symbolSnapshots;
1164    bool good = true;
1165    try
1166    {
1167        good = makeSymbolSnapshot(assembler, &symbolSnapshots, symEntry, outSymEntry,
1168                    parentExprSourcePos);
1169        if (good)
1170            for (AsmSymbolEntry* symEntry: symbolSnapshots)
1171                // delete evaluated symbol entries (except output symbol entry)
1172                if (outSymEntry != symEntry && symEntry->second.hasValue)
1173                {
1174                    delete symEntry->second.expression;
1175                    symEntry->second.expression = nullptr;
1176                    delete symEntry;
1177                }
1178                else
1179                    assembler.symbolSnapshots.insert(symEntry);
1180        else // if failed
1181            for (AsmSymbolEntry* symEntry: symbolSnapshots)
1182            {
1183                assembler.symbolSnapshots.erase(symEntry);
1184                delete symEntry->second.expression;
1185                symEntry->second.expression = nullptr;
1186                delete symEntry;
1187            }
1188    }
1189    catch(...)
1190    {
1191        for (AsmSymbolEntry* symEntry: symbolSnapshots)
1192        {
1193            assembler.symbolSnapshots.erase(symEntry);
1194            delete symEntry->second.expression;
1195            symEntry->second.expression = nullptr;
1196            delete symEntry;
1197        }
1198        throw;
1199    }   
1200    return good;
1201}
1202
1203AsmExpression* AsmExpression::createExprToEvaluate(Assembler& assembler) const
1204{
1205    TempSymbolSnapshotMap symbolSnapshots;
1206   
1207    try
1208    {
1209    size_t argsNum = 0;
1210    size_t msgPosNum = 0;
1211    for (AsmExprOp op: ops)
1212        if (AsmExpression::isArg(op))
1213            argsNum++;
1214    else if (operatorWithMessage & (1ULL<<int(op)))
1215        msgPosNum++;
1216    std::unique_ptr<AsmExpression> newExpr(new AsmExpression(
1217            sourcePos, symOccursNum, relativeSymOccurs, ops.size(), ops.data(),
1218            msgPosNum, messagePositions.get(), argsNum, args.get(), false));
1219    argsNum = 0;
1220    bool good = true;
1221    // try to resolve symbols
1222    for (AsmExprOp& op: newExpr->ops)
1223        if (AsmExpression::isArg(op))
1224        {
1225            if (op == AsmExprOp::ARG_SYMBOL) // if
1226            {
1227                AsmExprArg& arg = newExpr->args[argsNum];
1228                AsmSymbolEntry* symEntry = arg.symbol;
1229                if (symEntry!=nullptr && symEntry->second.base)
1230                    // create symbol snapshot if symbol is base
1231                    // only if for regular expression (not base
1232                    good &= newExpr->makeSymbolSnapshot(assembler, &symbolSnapshots,
1233                                *symEntry, symEntry, &sourcePos);
1234                if (symEntry==nullptr || !symEntry->second.hasValue)
1235                {
1236                    // no symbol not found
1237                    std::string errorMsg("Expression have unresolved symbol '");
1238                    errorMsg += symEntry->first.c_str();
1239                    errorMsg += '\'';
1240                    ASMX_NOTGOOD_BY_ERROR(sourcePos, errorMsg.c_str())
1241                }
1242                else
1243                {
1244                    if (symEntry->second.hasValue)
1245                    {
1246                        // resolve only if have symbol have value,
1247                        // but do not that if expression will be base for snapshot
1248                        if (!assembler.isAbsoluteSymbol(symEntry->second))
1249                        {
1250                            newExpr->relativeSymOccurs = true;
1251                            arg.relValue.sectionId = symEntry->second.sectionId;
1252                        }
1253                        arg.relValue.value = symEntry->second.value;
1254                        newExpr->symOccursNum--;
1255                        op = AsmExprOp::ARG_VALUE;
1256                    }
1257                }
1258            }
1259            argsNum++;
1260        }
1261   
1262    if (!good)
1263        return nullptr;
1264    // add expression into symbol occurrences in expressions
1265    for (AsmSymbolEntry* symEntry: symbolSnapshots)
1266    {
1267        if (!symEntry->second.hasValue)
1268            assembler.symbolSnapshots.insert(symEntry);
1269        else
1270        {
1271            // delete symbol snapshoft if have new value
1272            delete symEntry->second.expression;
1273            symEntry->second.expression = nullptr;
1274            delete symEntry;
1275        }
1276    }
1277    symbolSnapshots.clear();
1278    return newExpr.release();
1279    }
1280    catch(...)
1281    {
1282        // delete symbol snapshots if exception occurred
1283        for (AsmSymbolEntry* symEntry: symbolSnapshots)
1284        {
1285            // remove from assembler symbolSnapshots
1286            assembler.symbolSnapshots.erase(symEntry);
1287            // remove this snapshot
1288            delete symEntry->second.expression;
1289            symEntry->second.expression = nullptr;
1290            delete symEntry;
1291        }
1292        throw;
1293    }
1294}
1295
1296AsmExpression* AsmExpression::parse(Assembler& assembler, const char*& linePtr,
1297            bool makeBase, bool dontResolveSymbolsLater)
1298{
1299    struct ConExprOpEntry
1300    {
1301        AsmExprOp op;
1302        cxuint priority;
1303        size_t lineColPos;
1304    };
1305
1306    std::stack<ConExprOpEntry> stack;
1307    std::vector<AsmExprOp> ops;
1308    std::vector<AsmExprArg> args;
1309    std::vector<LineCol> messagePositions;
1310    std::vector<LineCol> outMsgPositions;
1311   
1312    TempSymbolSnapshotMap symbolSnapshots;
1313   
1314    try
1315    {
1316    const char* startString = linePtr;
1317    const char* end = assembler.line + assembler.lineSize;
1318    size_t parenthesisCount = 0;
1319    size_t symOccursNum = 0;
1320    bool good = true;
1321    bool relativeSymOccurs = false;
1322   
1323    // indicate what is expected at current place
1324    enum ExpectedToken
1325    {
1326        XT_FIRST = 0,   // operator or argument
1327        XT_OP = 1,  // expected operator
1328        XT_ARG = 2  // expected argument
1329    };
1330    ExpectedToken expectedToken = XT_FIRST;
1331    std::unique_ptr<AsmExpression> expr(new AsmExpression);
1332    expr->sourcePos = assembler.getSourcePos(startString);
1333   
1334    while (linePtr != end)
1335    {
1336        skipSpacesToEnd(linePtr, end);
1337        if (linePtr == end) break;
1338       
1339        LineCol lineCol = { 0, 0 };
1340        AsmExprOp op = AsmExprOp::NONE;
1341        bool expectedPrimaryExpr = false;
1342        //const size_t oldParenthesisCount = parenthesisCount;
1343        bool doExit = false;
1344       
1345        const char* beforeToken = linePtr;
1346        /* parse expression operator or value/symbol */
1347        switch(*linePtr)
1348        {
1349            case '(':
1350                if (expectedToken == XT_OP)
1351                    ASMX_NOTGOOD_BY_ERROR(linePtr, "Expected operator")
1352                else
1353                {
1354                    expectedToken = XT_FIRST;
1355                    parenthesisCount++;
1356                }
1357                linePtr++;
1358                break;
1359            case ')':
1360                if (expectedToken != XT_OP)
1361                    ASMX_NOTGOOD_BY_ERROR(linePtr, "Expected operator or value or symbol")
1362                else
1363                {
1364                    if (parenthesisCount==0)
1365                    { doExit = true; break; }
1366                    parenthesisCount--;
1367                }
1368                linePtr++;
1369                break;
1370            case '+':
1371                op = (expectedToken == XT_OP) ? AsmExprOp::ADDITION : AsmExprOp::PLUS;
1372                linePtr++;
1373                break;
1374            case '-':
1375                op = (expectedToken == XT_OP) ? AsmExprOp::SUBTRACT : AsmExprOp::NEGATE;
1376                linePtr++;
1377                break;
1378            case '*':
1379                op = AsmExprOp::MULTIPLY;
1380                linePtr++;
1381                break;
1382            case '/':
1383                lineCol = assembler.translatePos(linePtr);
1384                if (linePtr+1 != end && linePtr[1] == '/')
1385                {
1386                    op = AsmExprOp::DIVISION;
1387                    linePtr++;
1388                }
1389                else // standard GNU as signed division
1390                    op = AsmExprOp::SIGNED_DIVISION;
1391                linePtr++;
1392                break;
1393            case '%':
1394                lineCol = assembler.translatePos(linePtr);
1395                if (linePtr+1 != end && linePtr[1] == '%')
1396                {
1397                    op = AsmExprOp::MODULO;
1398                    linePtr++;
1399                }
1400                else // standard GNU as signed modulo
1401                    op = AsmExprOp::SIGNED_MODULO;
1402                linePtr++;
1403                break;
1404            case '&':
1405                if (linePtr+1 != end && linePtr[1] == '&')
1406                {
1407                    op = AsmExprOp::LOGICAL_AND;
1408                    linePtr++;
1409                }
1410                else // standard bitwise AND
1411                    op = AsmExprOp::BIT_AND;
1412                linePtr++;
1413                break;
1414            case '|':
1415                if (linePtr+1 != end && linePtr[1] == '|')
1416                {
1417                    op = AsmExprOp::LOGICAL_OR;
1418                    linePtr++;
1419                }
1420                else // standard bitwise OR
1421                    op = AsmExprOp::BIT_OR;
1422                linePtr++;
1423                break;
1424            case '!':
1425                if (expectedToken == XT_OP) // ORNOT or logical not
1426                {
1427                    if (linePtr+1 != end && linePtr[1] == '=')
1428                    {
1429                        // we have != (inequality operator)
1430                        op = AsmExprOp::NOT_EQUAL;
1431                        linePtr++;
1432                    }
1433                    else
1434                        op = AsmExprOp::BIT_ORNOT;
1435                }
1436                else
1437                    op = AsmExprOp::LOGICAL_NOT;
1438                linePtr++;
1439                break;
1440            case '~':
1441                if (expectedToken != XT_OP)
1442                    op = AsmExprOp::BIT_NOT;
1443                else
1444                    ASMX_NOTGOOD_BY_ERROR(linePtr,
1445                        "Expected non-unary operator, '(', or end of expression")
1446                linePtr++;
1447                break;
1448            case '^':
1449                op = AsmExprOp::BIT_XOR;
1450                linePtr++;
1451                break;
1452            case '<':
1453                if (linePtr+1 != end && linePtr[1] == '<')
1454                {
1455                    lineCol = assembler.translatePos(linePtr);
1456                    op = AsmExprOp::SHIFT_LEFT;
1457                    linePtr++;
1458                }
1459                else if (linePtr+1 != end && linePtr[1] == '>')
1460                {
1461                    op = AsmExprOp::NOT_EQUAL;
1462                    linePtr++;
1463                }
1464                else if (linePtr+1 != end && linePtr[1] == '=')
1465                {
1466                    // less or equal than (signed and unsigned)
1467                    if (linePtr+2 != end && linePtr[2] == '@')
1468                    {
1469                        op = AsmExprOp::BELOW_EQ;
1470                        linePtr++;
1471                    }
1472                    else
1473                        op = AsmExprOp::LESS_EQ;
1474                    linePtr++;
1475                }
1476                // less than (signed and unsigned)
1477                else if (linePtr+1 != end && linePtr[1] == '@')
1478                {
1479                    op = AsmExprOp::BELOW;
1480                    linePtr++;
1481                }
1482                else
1483                    op = AsmExprOp::LESS;
1484                linePtr++;
1485                break;
1486            case '>':
1487                if (linePtr+1 != end && linePtr[1] == '>')
1488                {
1489                    lineCol = assembler.translatePos(linePtr);
1490                    if (linePtr+2 != end && linePtr[2] == '>')
1491                    {
1492                        op = AsmExprOp::SIGNED_SHIFT_RIGHT;
1493                        linePtr++;
1494                    }
1495                    else
1496                        op = AsmExprOp::SHIFT_RIGHT;
1497                    linePtr++;
1498                }
1499                else if (linePtr+1 != end && linePtr[1] == '=')
1500                {
1501                    // greater or equal than (signed and unsigned)
1502                    if (linePtr+2 != end && linePtr[2] == '@')
1503                    {
1504                        op = AsmExprOp::ABOVE_EQ;
1505                        linePtr++;
1506                    }
1507                    else
1508                        op = AsmExprOp::GREATER_EQ;
1509                    linePtr++;
1510                }
1511                // greater than (signed and unsigned)
1512                else if (linePtr+1 != end && linePtr[1] == '@')
1513                {
1514                    op = AsmExprOp::ABOVE;
1515                    linePtr++;
1516                }
1517                else
1518                    op = AsmExprOp::GREATER;
1519                linePtr++;
1520                break;
1521            case '=':
1522                if (linePtr+1 != end && linePtr[1] == '=')
1523                {
1524                    op = AsmExprOp::EQUAL;
1525                    linePtr++;
1526                }
1527                else
1528                    expectedPrimaryExpr = true;
1529                linePtr++;
1530                break;
1531            case '?':
1532                lineCol = assembler.translatePos(linePtr);
1533                op = AsmExprOp::CHOICE_START;
1534                linePtr++;
1535                break;
1536            case ':':
1537                if (linePtr+1==end || linePtr[1]!=':')
1538                {
1539                    op = AsmExprOp::CHOICE;
1540                    linePtr++;
1541                    break;
1542                }
1543                // otherwise try parse symbol
1544            default: // parse symbol or value
1545                if (expectedToken != XT_OP)
1546                {
1547                    ExpectedToken oldExpectedToken = expectedToken;
1548                    expectedToken = XT_OP;
1549                    AsmSymbolEntry* symEntry;
1550                   
1551                    const char* symEndStr = linePtr;
1552                    Assembler::ParseState parseState = assembler.parseSymbol(symEndStr,
1553                                     symEntry, true, dontResolveSymbolsLater);
1554                    if (symEntry!=nullptr && symEntry->second.regRange)
1555                    {
1556                        ASMX_NOTGOOD_BY_ERROR(linePtr, "Expression have register symbol")
1557                        continue;
1558                    }
1559                   
1560                    if (parseState == Assembler::ParseState::FAILED) good = false;
1561                    AsmExprArg arg;
1562                    arg.relValue.sectionId = ASMSECT_ABS;
1563                    if (parseState != Assembler::ParseState::MISSING)
1564                    {
1565                        if (symEntry!=nullptr && symEntry->second.base && !makeBase)
1566                            // create symbol snapshot if symbol is base
1567                            // only if for regular expression (not base
1568                            good &= makeSymbolSnapshot(assembler, &symbolSnapshots,
1569                                      *symEntry, symEntry, &(expr->sourcePos));
1570                        if (symEntry==nullptr ||
1571                            (!symEntry->second.hasValue && dontResolveSymbolsLater))
1572                        {
1573                            // no symbol not found
1574                            std::string errorMsg("Expression have unresolved symbol '");
1575                            errorMsg.append(linePtr, symEndStr);
1576                            errorMsg += '\'';
1577                            ASMX_NOTGOOD_BY_ERROR(linePtr, errorMsg.c_str())
1578                        }
1579                        else
1580                        {
1581                            if (symEntry->second.hasValue && !makeBase)
1582                            {
1583                                // resolve only if have symbol have value,
1584                                // but do not that if expression will be base for snapshot
1585                                if (!assembler.isAbsoluteSymbol(symEntry->second))
1586                                {
1587                                    relativeSymOccurs = true;
1588                                    arg.relValue.sectionId = symEntry->second.sectionId;
1589                                }
1590                                arg.relValue.value = symEntry->second.value;
1591                                args.push_back(arg);
1592                                ops.push_back(AsmExprOp::ARG_VALUE);
1593                            }
1594                            else
1595                            {
1596                                /* add symbol */
1597                                symOccursNum++;
1598                                arg.symbol = symEntry;
1599                                args.push_back(arg);
1600                                ops.push_back(AsmExprOp::ARG_SYMBOL);
1601                            }
1602                        }
1603                        linePtr = symEndStr;
1604                    }
1605                    else if (parenthesisCount != 0 || (*linePtr >= '0' &&
1606                            *linePtr <= '9') || *linePtr == '\'')
1607                    {
1608                        // other we try to parse number
1609                        const char* oldStr = linePtr;
1610                        if (!assembler.parseLiteral(arg.value, linePtr))
1611                        {
1612                            arg.value = 0;
1613                            if (linePtr != end && oldStr == linePtr)
1614                                // skip one character when end is in this same place
1615                                // (avoids infinity loops)
1616                                linePtr++;
1617                            good = false;
1618                        }
1619                        args.push_back(arg);
1620                        ops.push_back(AsmExprOp::ARG_VALUE);
1621                    }
1622                    else
1623                    {
1624                        // otherwise we finish parsing
1625                        expectedToken = oldExpectedToken;
1626                        doExit = true; break;
1627                    }
1628                }
1629                else
1630                {
1631                    // otherwise we exit if no left parenthesis
1632                    if (parenthesisCount == 0)
1633                    { doExit = true; break; }
1634                    else
1635                    {
1636                        linePtr++;
1637                        ASMX_NOTGOOD_BY_ERROR(linePtr, "Garbages at end of expression")
1638                    }
1639                }
1640        }
1641       
1642        if (op != AsmExprOp::NONE && !isUnaryOp(op) && expectedToken != XT_OP)
1643        {
1644            expectedPrimaryExpr = true;
1645            op = AsmExprOp::NONE;
1646        }
1647        // when no argument before binary/ternary operator
1648        if (expectedPrimaryExpr)
1649        {
1650            ASMX_NOTGOOD_BY_ERROR(beforeToken,
1651                     "Expected primary expression before operator")
1652            continue;
1653        }
1654       
1655        // determine what is next expected
1656        if (op != AsmExprOp::NONE && !isUnaryOp(op))
1657            expectedToken = (expectedToken == XT_OP) ? XT_ARG : XT_OP;
1658       
1659        //afterParenthesis = (oldParenthesisCount < parenthesisCount);
1660        const size_t lineColPos = (lineCol.lineNo!=0) ? messagePositions.size() : SIZE_MAX;
1661        if (lineCol.lineNo!=0)
1662            messagePositions.push_back(lineCol);
1663       
1664        if (op != AsmExprOp::NONE)
1665        {
1666            // if operator
1667            const bool unaryOp = isUnaryOp(op);
1668            const cxuint priority = (parenthesisCount<<3) +
1669                        asmOpPrioritiesTbl[cxuint(op)];
1670           
1671            if (op == AsmExprOp::CHOICE)
1672            {
1673                /* second part of choice */
1674                while (!stack.empty())
1675                {
1676                    const ConExprOpEntry& entry = stack.top();
1677                    if (priority > entry.priority || (priority == entry.priority &&
1678                        entry.op == AsmExprOp::CHOICE_START))
1679                        break;
1680                    if (entry.op != AsmExprOp::PLUS)
1681                        ops.push_back(entry.op);
1682                    if (entry.lineColPos != SIZE_MAX && entry.op != AsmExprOp::CHOICE_START)
1683                        outMsgPositions.push_back(messagePositions[entry.lineColPos]);
1684                    stack.pop();
1685                }
1686                if (stack.empty())
1687                {
1688                    linePtr--; // go back to ':'
1689                    expectedToken = XT_OP;
1690                    doExit = true;
1691                    break;
1692                }
1693                else if (stack.top().op != AsmExprOp::CHOICE_START ||
1694                        stack.top().priority != priority)
1695                {
1696                    // not found
1697                    ASMX_NOTGOOD_BY_ERROR(beforeToken, "Missing '?' before ':'")
1698                    continue; // do noy change stack and them entries
1699                }
1700                ConExprOpEntry& entry = stack.top();
1701                entry.op = AsmExprOp::CHOICE;
1702                entry.lineColPos = SIZE_MAX;
1703            }
1704            else
1705            {
1706                while (!stack.empty())
1707                {
1708                    const ConExprOpEntry& entry = stack.top();
1709                    if (priority +
1710                        /* because ?: is computed from right to left we adds 1 to priority
1711                         * to force put new node higher than left node */
1712                        (op == AsmExprOp::CHOICE_START) + unaryOp > entry.priority)
1713                        break;
1714                    if (entry.op == AsmExprOp::CHOICE_START)
1715                    {
1716                        // unfinished choice
1717                        stack.pop();
1718                        ASMX_NOTGOOD_BY_ERROR(messagePositions[entry.lineColPos],
1719                                 "Missing ':' for '?'")
1720                        break;
1721                    }
1722                    if (entry.op != AsmExprOp::PLUS)
1723                        ops.push_back(entry.op);
1724                    if (entry.lineColPos != SIZE_MAX && entry.op != AsmExprOp::CHOICE_START)
1725                        outMsgPositions.push_back(messagePositions[entry.lineColPos]);
1726                    stack.pop();
1727                }
1728                stack.push({ op, priority, lineColPos });
1729            }
1730        }
1731       
1732        if (doExit) // exit from parsing
1733            break;
1734    }
1735    if (parenthesisCount != 0) // print error
1736        ASMX_NOTGOOD_BY_ERROR(linePtr, "Missing ')'")
1737    if (expectedToken != XT_OP)
1738    {
1739        if (!ops.empty() || !stack.empty())
1740            ASMX_NOTGOOD_BY_ERROR(linePtr, "Unterminated expression")
1741    }
1742    else
1743    {
1744        while (!stack.empty())
1745        {
1746            const ConExprOpEntry& entry = stack.top();
1747            if (entry.op == AsmExprOp::CHOICE_START)
1748            {
1749                // unfinished choice
1750                ASMX_NOTGOOD_BY_ERROR(messagePositions[entry.lineColPos],
1751                         "Missing ':' for '?'")
1752                break;
1753            }
1754            if (entry.op != AsmExprOp::PLUS)
1755                ops.push_back(entry.op);
1756            if (entry.lineColPos != SIZE_MAX && entry.op != AsmExprOp::CHOICE_START)
1757                outMsgPositions.push_back(messagePositions[entry.lineColPos]);
1758            stack.pop();
1759        }
1760    }
1761   
1762    if (good)
1763    {
1764        const size_t argsNum = args.size();
1765        // if good, we set symbol occurrences, operators, arguments ...
1766        expr->setParams(symOccursNum, relativeSymOccurs,
1767                  ops.size(), ops.data(), outMsgPositions.size(), outMsgPositions.data(),
1768                  argsNum, args.data(), makeBase);
1769        if (!makeBase)
1770        {
1771            // add expression into symbol occurrences in expressions
1772            // only for non-base expressions
1773            for (size_t i = 0, j = 0; j < argsNum; i++)
1774                if (ops[i] == AsmExprOp::ARG_SYMBOL)
1775                {
1776                    args[j].symbol->second.addOccurrenceInExpr(expr.get(), j, i);
1777                    j++;
1778                }
1779                else if (ops[i]==AsmExprOp::ARG_VALUE)
1780                    j++;
1781        }
1782        for (AsmSymbolEntry* symEntry: symbolSnapshots)
1783        {
1784            if (!symEntry->second.hasValue)
1785                assembler.symbolSnapshots.insert(symEntry);
1786            else
1787            {
1788                // delete symbol snapshoft if have new value
1789                delete symEntry->second.expression;
1790                symEntry->second.expression = nullptr;
1791                delete symEntry;
1792            }
1793        }
1794        symbolSnapshots.clear();
1795        return expr.release();
1796    }
1797    else
1798    {
1799        // delete symbol snapshots if error
1800        for (AsmSymbolEntry* symEntry: symbolSnapshots)
1801        {
1802            delete symEntry->second.expression;
1803            symEntry->second.expression = nullptr;
1804            delete symEntry;
1805        }
1806        return nullptr;
1807    }
1808    }
1809    catch(...)
1810    {
1811        // delete symbol snapshots if exception occurred
1812        for (AsmSymbolEntry* symEntry: symbolSnapshots)
1813        {
1814            // remove from assembler symbolSnapshots
1815            assembler.symbolSnapshots.erase(symEntry);
1816            // remove this snapshot
1817            delete symEntry->second.expression;
1818            symEntry->second.expression = nullptr;
1819            delete symEntry;
1820        }
1821        throw;
1822    }
1823}
1824
1825// go to top in expression from specified operator index (can be used to divide expression)
1826size_t AsmExpression::toTop(size_t opIndex) const
1827{
1828    std::stack<cxbyte> stack;
1829    while (true)
1830    {
1831        AsmExprOp op = ops[opIndex];
1832        if (op==AsmExprOp::ARG_VALUE)
1833        {
1834            while (!stack.empty() && --stack.top()==0)
1835                stack.pop();
1836            if (stack.empty())
1837                break; // is end
1838        }
1839        else // operators
1840            stack.push(isUnaryOp(op) ? 1 : (isBinaryOp(op) ? 2 : 3));
1841        opIndex--;
1842    }
1843    return opIndex;
1844}
1845
1846static const uint32_t acceptedCharsAfterFastExpr =
1847    (1U<<('!'-32)) | (1U<<('%'-32)) | (1U<<('&'-32)) | (1U<<('*'-32)) | (1U<<('!'-32)) |
1848        (1U<<('+'-32)) | (1U<<('-'-32)) | (1U<<('/'-32)) | (1U<<('<'-32)) |
1849        (1U<<('='-32)) | (1U<<('>'-32)) | (1U<<('?'-32));
1850
1851bool AsmExpression::fastExprEvaluate(Assembler& assembler, const char*& linePtr,
1852                        uint64_t& value)
1853{
1854    const char* end = assembler.line + assembler.lineSize;
1855    uint64_t sum = 0;
1856    bool addition = true;
1857    const char* tmpLinePtr = linePtr;
1858    skipSpacesToEnd(tmpLinePtr, end);
1859   
1860    // main loop
1861    while (true)
1862    {
1863        // loop for chain of unary '+' and '-'
1864        while (tmpLinePtr != end && (*tmpLinePtr=='+' || *tmpLinePtr=='-'))
1865        {
1866            if (*tmpLinePtr=='-')
1867                addition = !addition;
1868            skipCharAndSpacesToEnd(tmpLinePtr, end);
1869        }
1870        uint64_t tmp = 0;
1871        if (tmpLinePtr == end || (!isDigit(*tmpLinePtr) && *tmpLinePtr!='\''))
1872            return false;
1873        if (!assembler.parseLiteralNoError(tmp, tmpLinePtr))
1874            return false;
1875        if (tmpLinePtr!=end && (*tmpLinePtr=='f' || *tmpLinePtr=='b'))
1876        {   // if local label
1877            const char* t = tmpLinePtr-1;
1878            while (t!=linePtr-1 && isDigit(*t)) t--;
1879            if (t==linePtr-1 || isSpace(*t)) // if local label
1880                return false;
1881        }
1882        // add or subtract
1883        sum += addition ? tmp : -tmp;
1884        // skip to next '+' or '-'
1885        skipSpacesToEnd(tmpLinePtr, end);
1886        if (tmpLinePtr==end || (*tmpLinePtr!='+' && *tmpLinePtr!='-'))
1887            break; // end
1888        // otherwise we continue
1889        addition = (*tmpLinePtr=='+');
1890        skipCharAndSpacesToEnd(tmpLinePtr, end);
1891    }
1892    if (tmpLinePtr==end ||
1893        // check whether is not other operator
1894        (*tmpLinePtr!='~' && *tmpLinePtr!='^' && *tmpLinePtr!='|' &&
1895        (*tmpLinePtr<32 || *tmpLinePtr>=64 ||
1896        // check whether is not other operator (by checking rest of characters)
1897        ((1U<<(*tmpLinePtr-32)) & acceptedCharsAfterFastExpr)==0)))
1898    {
1899        value = sum;
1900        linePtr = tmpLinePtr;
1901        return true;
1902    }
1903    return false;
1904}
1905
1906bool AsmExpression::fastExprEvaluate(Assembler& assembler, size_t& linePos,
1907                        uint64_t& value)
1908{
1909    const char* linePtr = assembler.line + linePos;
1910    bool res = fastExprEvaluate(assembler, linePtr, value);
1911    linePos = linePtr - assembler.line;
1912    return res;
1913}
Note: See TracBrowser for help on using the repository browser.