How are operators organized/saved in the memory in context of a programming language. Are they procedures/functions saved somewhere and compilers just manipulate things to call these procs whenever the operators are used in the program?
- Anybody can ask a question
- Anybody can answer
- The best answers are voted up and rise to the top
Most operators are just "syntactic sugar" for functions or procedures, so you can look at them mostly the same way:
The parser converts it first into an abstract syntax tree. The kind of operator ends up as a node, and the operands end up as its child nodes. The compiler then basically walks the abstract syntax tree and does different things depending on the types of the operands.
Most of the time, the operator code is going to be simple enough to inline. However, there are also situations where it's complex enough to create a function call. For example, in C++ you can override operators on classes by creating your own functions to handle them. Usually in simple, interpreted domain specific languages it also ends up as a function call because that's the easiest way to do it when performance isn't paramount.
The compiler plays most important role in this case. Compilers may act differently depending on which programming language and version are you using.
For more detailed information here is a nice article to look - Operator (programming) - Wiki
In compiled languages, entire expressions, including the operators that they contain, get transformed to binary code corresponding to the calculation represented by the expression. An operator gets translated into a sequence of one or more binary instructions to the CPU, directing it to perform the required operation. For example
may get converted into something like this:
If an operator does not correspond to a single assembly instruction, a compiler implementation may choose an inlined or a non-inlined function to implement it. For example, in 8-bit CPUs that lacked multiplication instructions (and were short on memory, restricting the opportunities for inlining, e.g. 6502), multiplication and division have been commonly implemented as subroutines.
In interpreted languages operators are stored as part of the code, in the form of a data structure if preprocessing is used, or in their textual form in the rare case when preprocessing is not used.
In a language like C or C++, simple native types like int, char, float, double in full features architectures with floating point hardware may typically become sequential machine instructions like the other statements in the code block.
In an architecture that does not have native floating point hardware (or even 32 bit ints), simple expressions may generate subroutine calls to run time libraries that supplement the device's basic capabilities. I did an experiment with some eight bit micros vs. an X86 compiler a few years back and found big differences in the size of code generated. x86 was 1/3 as big, and unlike the 8 bit architectures that had many run time calls for simple things like adding 32-bit and 64-bit integers, it was all generated by instructions sequences.
Often constants are inserted with the instructions as immediate operands. In some architectures, the immediate data will be pushed on the stack or written relative to a stack pointer or a base pointer. In an executable, the inserted instructions and the immediate operands will typically be in the code segment. For complex data like arrays, strings, and user defined variables, if they are constant, they too may be emitted to a code segment, but what is more common is that during run time they are copied to a data segment that is initialized by the loader or the run time system.
Compilers have many methods of optimizing expressions, so if you single step and see what seems like very few instructions relative to an expression, it may mean that the constants in the expression were simplified. There is also a technique in which common subexpressions are evaluated once before the first usage, then when needed again, the partial result is just used from a temporary variable or a register.
This group, or Stack Exchange Code Review would perhaps be a great venue to explain what is happening if you have additional questions about a block of source code and the machine instructions that it generates, particularly as relates to compiler optimizations.
When operators or expressions are used with complex data types like arrays, strings, structs, or classes, there may be some cases where things are performed sequentially, but generally, more complex types required functions calls. A worthwhile exception to this is when a compiler provides OpenMP extensions that perform fine grain parallelism on small blocks of code that is dispatched across multiple cores. But as interesting as it might be, the details are probably out of scope for this question.