<p>So, here is how strings work in <a href="https://github.com/FlatAssembler/AECforWebAssembly.git" rel="nofollow noreferrer">my AEC-to-WebAssembly compiler</a>. After the program is parsed, all strings except inline assembly ones are gathered in a C++ <code>std::set&lt;std::string&gt;</code>, like <a href="https://github.com/FlatAssembler/AECforWebAssembly/blob/eb4950eeedd1b4afe81a29b5415e1d95a7cdc681/TreeNode.cpp#L32C1-L53C1" rel="nofollow noreferrer">this</a>:</p>
<pre class="lang-cpp prettyprint-override"><code>protected:
  std::set&lt;std::string&gt; getStringsInSubnodes() const {
    auto setToBeReturned = std::set&lt;std::string&gt;();
    if (text == &quot;asm(&quot; or text == &quot;asm_i32(&quot; or text == &quot;asm_i64(&quot; or
        text == &quot;asm_f32(&quot; or
        text == &quot;asm_f64(&quot;) // Inline assembly isn't a string that can be
                            // manipulated, and storing it in memory wastes
                            // memory (potentially a lot of it).
      return std::set&lt;std::string&gt;(); // That's why we will return an empty set,
                                      // as if we had no strings in our subnodes
                                      // (even though we have at least one).
    if (text.size() and text[0] == '&quot;') {
      setToBeReturned.insert(text);
      return setToBeReturned;
    }
    for (auto child : children) {
      auto stringsInChild = child.getStringsInSubnodes();
      setToBeReturned.insert(stringsInChild.begin(), stringsInChild.end());
    }
    return setToBeReturned;
  }
</code></pre>
<p>And then my compiler marks all the strings as if they were variables with the type <code>CharacterPointer</code>, and stores them at the beginning of the heap memory (starting as the 4096th byte in the WebAssembly memory), like <a href="https://github.com/FlatAssembler/AECforWebAssembly/blob/eb4950eeedd1b4afe81a29b5415e1d95a7cdc681/TreeRootNode.cpp#L161C1-L171C6" rel="nofollow noreferrer">this</a> (<code>context.globalVariablePointer</code> is supposed to be set at <code>4096</code> before this is run):</p>
<pre class="lang-cpp prettyprint-override"><code>    auto allTheStrings = getStringsInSubnodes();
    for (auto string : allTheStrings) {
      context.globalVariables[string] = context.globalVariablePointer;
      context.variableTypes[string] = &quot;CharacterPointer&quot;;
      if (string.back() != '&quot;')
        string += '&quot;';
      globalDeclarations += &quot;\t(data 0 (i32.const &quot; +
                            std::to_string(context.globalVariablePointer) +
                            &quot;) &quot; + string + &quot;)\n&quot;;
      context.globalVariablePointer += string.size() - 1;
    }
</code></pre>
<p>So, let's say I want to add the <code>typeid</code> operator to AEC, which will take anything as an argument and return its type as a string. How would I go about doing that? Since the strings are dealt with right after parsing, it's before the types of expressions are being determined. I cannot add a special case in my <code>getStringsInSubnodes</code> method for the <code>typeid</code> operator and return a string representing the type in that case, because determining the type of a an expression requires the compilation context (to know how each variable or structure was defined), and <code>getStringsInSubnodes()</code> doesn't even accept the compilation context as an argument (as it was not supposed to be constructed before it is called). So, how might I solve that problem?</p>

<compilers><types><c++><strings><webassembly>
How might I implement a `typeid` operator (returning the type of its argument as something, presumably as a string) in my compiler?
<p>There are a lot of things that you still need to implement in your compiler, and there are several ways to do the same thing.</p>
<p>You need to implement a &quot;type system&quot; or &quot;type data dictionary&quot;, not just strings.</p>
<p>A type system is a list of types that your compiler supports, starting with the predefined types, and later the types the programmer is creating, and assigning each type an ID, either integer, string or uuid that is NOT the name of the type.</p>
<p>Example:</p>
<pre><code>enum TypeCategoryEnum
{
  Unassigned,
  SimpleType,
  StructType,
  ClassType,
  ArrayType,
  EnumType,
  UnionType,
  PointerType,  
  FunctorType
};

struct TypeInfoStruct
{
  uuid TypeId;
  char[256] TypeName;
  enum TypeCategoryEnum TypeCategory;
  bool IsPredefined;
};
</code></pre>
<p>You will need operations to add, or search for types by name or ID.</p>
<p>Each node of the AST must have a TypeID, that will have the value unassigned if it's not a variable, constant or value like a keyword.</p>
<p>Otherwise, will store the ID to the given type.</p>
<p>Each type a new type is created, such as in a &quot;struct&quot; or &quot;union&quot; that type is added to the type dictionary.</p>
<p>TypeID function just return the ID of the given string, by locating the AST node.</p>
<p>There are other ways to do this like using directly the string name of each type, but not recommended.</p>

CC BY-SA 4.0
2024-12-15T00:38:19.467Z
2024-12-17T20:44:00.383Z
2024-12-17T20:44:00.383Z
umlcat
CC BY-SA 4.0
2024-12-17T14:43:23.783Z
With this approach it'd be most natural to extract (and then store) all TypeName strings at the point those TypeInfoStruct begin to exist. But then many strings may not ever be used. Is there a way to avoid generating extra strings? Or perhaps the only option is a post-processing phase to remove unused strings...
Pablo H
CC BY-SA 4.0
2024-12-17T20:42:41.943Z
@PabloH I guess it-s the postprocessing, usually the unused strings are ignored. Are you sure you are not confusing "token IDs" with "type Ids" ???
umlcat
# How might I implement a `typeid` operator (returning the type of its argument as something, presumably as a string) in my compiler?
Posted by: username_0 on 2024-12-14
So, here is how strings work in my AEC-to-WebAssembly compiler. After the program is parsed, all strings except inline assembly ones are gathered in a C++ std::set, like this:
protected:
  std::set getStringsInSubnodes() const {
    auto setToBeReturned = std::set();
    if (text == "asm(" or text == "asm_i32(" or text == "asm_i64(" or
        text == "asm_f32(" or
        text == "asm_f64(") // Inline assembly isn't a string that can be
                            // manipulated, and storing it in memory wastes
                            // memory (potentially a lot of it).
      return std::set(); // That's why we will return an empty set,
                                      // as if we had no strings in our subnodes
                                      // (even though we have at least one).
    if (text.size() and text[0] == '"') {
      setToBeReturned.insert(text);
      return setToBeReturned;
    }
    for (auto child : children) {
      auto stringsInChild = child.getStringsInSubnodes();
      setToBeReturned.insert(stringsInChild.begin(), stringsInChild.end());
    }
    return setToBeReturned;
  }

And then my compiler marks all the strings as if they were variables with the type CharacterPointer, and stores them at the beginning of the heap memory (starting as the 4096th byte in the WebAssembly memory), like this (context.globalVariablePointer is supposed to be set at 4096 before this is run):
    auto allTheStrings = getStringsInSubnodes();
    for (auto string : allTheStrings) {
      context.globalVariables[string] = context.globalVariablePointer;
      context.variableTypes[string] = "CharacterPointer";
      if (string.back() != '"')
        string += '"';
      globalDeclarations += "\t(data 0 (i32.const " +
                            std::to_string(context.globalVariablePointer) +
                            ") " + string + ")\n";
      context.globalVariablePointer += string.size() - 1;
    }

So, let's say I want to add the typeid operator to AEC, which will take anything as an argument and return its type as a string. How would I go about doing that? Since the strings are dealt with right after parsing, it's before the types of expressions are being determined. I cannot add a special case in my getStringsInSubnodes method for the typeid operator and return a string representing the type in that case, because determining the type of a an expression requires the compilation context (to know how each variable or structure was defined), and getStringsInSubnodes() doesn't even accept the compilation context as an argument (as it was not supposed to be constructed before it is called). So, how might I solve that problem?
**Tags:** compilers types c++ strings webassembly
---
## 1 answers
### Answer by username_1 on 2024-12-15. Score: 1 | Accepted answer
There are a lot of things that you still need to implement in your compiler, and there are several ways to do the same thing.
You need to implement a "type system" or "type data dictionary", not just strings.
A type system is a list of types that your compiler supports, starting with the predefined types, and later the types the programmer is creating, and assigning each type an ID, either integer, string or uuid that is NOT the name of the type.
Example:
enum TypeCategoryEnum
{
  Unassigned,
  SimpleType,
  StructType,
  ClassType,
  ArrayType,
  EnumType,
  UnionType,
  PointerType,  
  FunctorType
};

struct TypeInfoStruct
{
  uuid TypeId;
  char[256] TypeName;
  enum TypeCategoryEnum TypeCategory;
  bool IsPredefined;
};

You will need operations to add, or search for types by name or ID.
Each node of the AST must have a TypeID, that will have the value unassigned if it's not a variable, constant or value like a keyword.
Otherwise, will store the ID to the given type.
Each type a new type is created, such as in a "struct" or "union" that type is added to the type dictionary.
TypeID function just return the ID of the given string, by locating the AST node.
There are other ways to do this like using directly the string name of each type, but not recommended.
> **Comments:**
> **username_2** (2024-12-17): With this approach it'd be most natural to extract (and then store) all TypeName strings at the point those TypeInfoStruct begin to exist. But then many strings may not ever be used. Is there a way to avoid generating extra strings? Or perhaps the only option is a post-processing phase to remove unused strings...  
> **username_1** (2024-12-17): @PabloH I guess it-s the postprocessing, usually the unused strings are ignored. Are you sure you are not confusing "token IDs" with "type Ids" ???  
---
