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?
Most operators are just "syntactic sugar" for functions or procedures, so you can look at them mostly the same way:
- They may be ordinary lists of machine instructions stored at a particular address to be called like an ordinary function. Sometimes these functions are actually callable as normal functions if you know the correct syntax, but in other situations/languages it may be that the compiler handles it completely internally without granting developers access to the functionality through anything but the compiler's own lexer and parser.
- Sometimes the compiler can replace the operator at the place it is called, in the source, to avoid the overhead of the machine instructions needed for a function call, directly placing the machine code there (i.e. like inlining, in some cases EXACTLY like inlining).
- Sometimes you might be working in an interpreter / runtime, where the functions are stored in an intermediate language which is "interpreted" by the runtime for the correct machine code, which could conceivably also be inlined but would still need to be interpreted.
- In some cases, where the operands of the operator are types that are very close or identical to the machine code instruction set the operators may get translated directly into only very few statements. How many statements would mostly depend on whether the operands involved are currently stored in registers or memory (which is a whole compiler topic on its own).
- In nearly all cases, what actually happens inside the compiler, interpreter or runtime will depend on the types of the operands. An operator between two operands of the same type will end up resolving to the operator for that type (which may or may not be entirely different from the same operator for different types). An operator between operands of different types may be implemented directly (which is rare) or additionally call conversion operators on one or more of the operands to turn them into types that can be operated on, before actually performing the operator itself.
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.
whole file and code that it contains is loaded to the memory. The reserved expressions like operators and commands are treated in different ways by each different compiler.
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
a = b + 2;
may get converted into something like this:
LOAD R1, @b LOAD R0, #2 ADD R0, R1 STORE R0, @a
@b represent addresses of variables
#2 represents the value of an integer constant
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.