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

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

CLRadeonExtender: Asm: First stuff to handle section differences (untested and not working).

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