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

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

CLRadeonExtender: AsmExpr?: Rewrite sectionDiffs support.

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