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

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

CLRadeonExtender: Asm: Tentative implementation of '.for' pseudo-op (repetition).

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